我正在尝试编写一个程序,其中我从父母那里分配一个孩子,并使用处理程序处理SIGCHLD信号,我在其中使用waitpid()。但是,当我执行它时,我有时会从waitpid获得0的返回值,并且errno被设置为EINTR。这是什么意思?
这是我的SIGCHLD处理程序:
pid_t pid;
int status;
while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0)
{
printf("Handler reaped child %d\n", (int)pid);
if(WIFEXITED(status))
{
deletejob(job_list, pid);
}
else if(WIFSIGNALED(status))
{
deletejob(job_list, pid);
}
else if(WIFSTOPPED(status))
{
struct job_t *job = getjobpid(job_list, pid);
job->state = ST;
}
}
printf("%d %d\n", pid, errno);
if(errno != ECHILD)
{
unix_error("waitpid error");
}
return;
这是父函数,我在其中分叉子:
pid_t pid;
sigset_t block_set;
int file_descriptor;
if(tok.outfile == NULL)
{
file_descriptor = STDOUT_FILENO;
}
else
{
file_descriptor = open(tok.outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
}
sigemptyset(&block_set);
sigaddset(&block_set, SIGCHLD);
sigaddset(&block_set, SIGINT);
sigaddset(&block_set, SIGTSTP);
sigprocmask(SIG_BLOCK, &block_set, NULL);
pid = fork();
if(pid == 0)
{
sigprocmask(SIG_UNBLOCK, &block_set, NULL);
setpgid(0, 0);
dup2(file_descriptor, 1);
while(execve(tok.argv[0], tok.argv, environ) < 0)
{
exit(0);
}
}
else
{
if(bg == 1)
{
addjob(job_list, pid, BG, cmdline);
sigprocmask(SIG_UNBLOCK, &block_set, NULL);
int jid = pid2jid(pid);
printf("[%d] (%d) %s\n", jid, pid, cmdline);
}
else if(bg == 0)
{
addjob(job_list, pid, FG, cmdline);
sigprocmask(SIG_UNBLOCK, &block_set, NULL);
}
if(bg == 0)
{
struct job_t *job = getjobpid(job_list, pid);
while(pid == fgpid(job_list))
{
sleep(1);
}
}
}
}
return;
答案 0 :(得分:3)
当使用WNOHANG
跟注时,waitpid()
会在没有更多孩子收获时返回0
。当子进程退出时,会调用您的SIGCHLD
处理程序,因此您知道总会有至少一个处理器收到。但是因为多个信号没有排队,所以可能有多个子进程可以收获。
那么while
循环的作用是什么:
while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0)
基本上是说“呼叫waitpid()
收获我知道正在等待的孩子,然后一遍又一遍地呼叫它以收获可能碰巧可用的任何其他孩子,直到它返回{{1} },此时我知道我收集了所有可用的孩子。“
因此,返回0
不是一个错误,它是一个有意识的设备来收获未知数量的孩子。在这种情况下,0
未设置waitpid()
,因此必须在某些先前的系统调用中断时设置errno
。
一般来说,除非函数返回错误,否则不应检查EINTR
,尽管存在一些异常情况(errno
为1,strtol()
的返回可能意味着已解析number为0
,或者可能表示存在错误)返回值未明确指示错误。在这些情况下,您可以在调用函数之前将0
设置为errno
,如果返回值表明可能是错误,则可以检查{{1查看是否已设置。