我正在编写一个多线程应用程序(学校项目,修改过河问题)。 我正在使用POSIX信号量,共享内存和fork函数。主流程创建了2个流程。然后他们每个人创建N个进程。每个过程代表一个人。我想知道什么是专业技术/最好的方法让父母等到他们所有的孩子,直到他们完成,然后获得他们的退出代码。我不能/不能使用像:
这样的结构while (wait(NULL) > 0)
;
// parent code
使用共享变量的结构都不像
while (1)
if (num_of_processes == num_of_finished_processes)
break;
// parent_code
注意:num_of_processes是传递给程序
的参数我可以以某种方式使用信号量告诉父母:“现在醒来并执行你的代码”。 用一句话。我不想使用主动/循环等待。 谢谢你的任何建议。我只是这个领域的初学者。
答案 0 :(得分:1)
“专业”的定义可以是弹性的。
基本上有两个原因可以收获你的孩子:避免僵尸在进程表中占用空间并询问孩子的返回码和(可能)基于他们的一些行动。这两个都可以指出,在所有条件相同的情况下,尽可能快地收获它们。
所以你的选择是:
wait
或waitpid
等待它们。waitpid
和WNOHANG选项signalfd
(在Linux上)但这仍然需要轮询或使用select/poll/epoll
因为你拒绝了1& 2(并隐式4)留下处理信号和使用处理程序。出于心理健康的原因,如果不一定是专业性,大多数人尽可能地避免信号,如果他们不必这样做,就不去寻找处理它们的方法,因为:
信号处理程序有自己的约束,主要是您希望尽快进出它们,并且您应该在其中使用有限数量的异步安全函数。所以这通常意味着在处理程序中记录任何内容,并在主程序或专用程序中处理信息。
由于您已选择处理信号(SIGCHLD),因此您已经承担了系统调用被中断的后果。由于您使用的是POSIX信号量,因此sem_wait
会特别受到关注。您可以通过在建立处理程序时通过sigaction
调用打开SA_RESTART标志来绕过大多数,但即使有标志,也会有一些不会自动重新启动的调用。
多线程和信号带来了一系列令人头疼的问题。
以下是上述一些问题的粗略但有说服力的例子:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
typedef struct childInfo
{
pid_t childPid;
int childstatus;
} childInfo;
static volatile sig_atomic_t numberOfChildren = 0;
static volatile sig_atomic_t childrenReaped = 0;
childInfo *childrenTable;
void saveStatus(pid_t pid, int status)
{
for (int i = 0; i < numberOfChildren; ++i)
{
if (pid == childrenTable[i].childPid)
childrenTable[i].childstatus = status;
}
}
void printChildrenStatus()
{
for (int i = 0; i < numberOfChildren; ++i)
{
if (childrenTable[i].childPid != 0)
{
if (WIFEXITED(childrenTable[i].childstatus))
printf("PID %d exited normally. "
"Exit status: %d\n",
childrenTable[i].childPid, WEXITSTATUS(childrenTable[i].childstatus));
else
if (WIFSTOPPED(childrenTable[i].childstatus))
printf("PID %d was stopped by %d\n",
childrenTable[i].childPid,
WSTOPSIG(childrenTable[i].childstatus));
else
if (WIFSIGNALED(childrenTable[i].childstatus))
printf("PID %d exited due to signal %d\n.",
childrenTable[i].childPid,
WTERMSIG(childrenTable[i].childstatus));
childrenTable[i].childPid = 0;
childrenReaped++;
}
}
}
void childHandler(int signum)
{
int childstatus;
pid_t childpid;
while ((childpid = waitpid( -1, &childstatus, WNOHANG)) > 0)
saveStatus(childpid, childstatus);
}
int main(int argc, char *argv[])
{
if (argc > 1)
numberOfChildren = atoi(argv[1]);
else
{
printf("must enter num of children to create...");
exit(1);
}
childrenTable = calloc(numberOfChildren, sizeof(childInfo));
struct sigaction sa;
sa.sa_handler = childHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART; // Restart functions, particularly your parent's
// sem_wait if interrupted by the handler
if (sigaction(SIGINT, &sa, NULL) == -1)
{
perror("sigaction");
exit(1);
}
for (int i = 0; i < numberOfChildren; ++i)
{
pid_t pid = fork();
if (pid)
childrenTable[i].childPid = pid;
else
{
sleep(i);
exit(0);
}
}
while(numberOfChildren - childrenReaped)
{
pause();
printChildrenStatus();
}
return(0);
}
答案 1 :(得分:0)
while ( wait(NULL) > 0 )
是一个infine循环,因为wait(2)
的返回值是已终止子进程的pid,即!= 0
,并且不会更改。
如果您希望父进程等待N
进程退出,您只需使用这样的循环:
for (i = 0; i < N; ++i)
wait(NULL);