fork + wait在OSX上获取EINTR

时间:2013-12-12 22:25:38

标签: c macos unix fork

我在fork 101失败了。我希望这会分叉一个子进程,并输出子和父printfs:

pid_t fpid;

if ((fpid = fork()) < 0)
{
    printf("fork: %s\n", strerror(errno));
    exit(-1);
}

if (0 == fpid) // child
{
    printf("\nI am the child\n");
}
else
{
    printf("\nI am the parent\n");
    pid_t wpid;
    while ((wpid = waitpid(WAIT_ANY, NULL, 0)))
    {
        if (errno == ECHILD)
            break;
        else if (wpid < 0)
            printf("wait: %s\n", strerror(errno));
    }
}

相反,我得到了这个输出:

  

我是父母

     

等待:系统调用中断

所以我的问题是:为什么孩子没有机会生活和奔跑?请不要有人想到孩子们!此外,EINTR来自哪里?显然,这与我的第一个问题有某种关系。

此外,当我在独立程序中运行该代码时,它可以正常工作,但不能在我的更大程序中运行;大型程序可以做些什么来扰乱waitpid?

FWIW这是在OSX 10.9上。

2 个答案:

答案 0 :(得分:4)

在OSX上,在fork之前/之后对fork的子端做很多事情是不合法的。请参阅fork man page底部的警告。安全功能列表位于sigaction(2) man pageprintf()不在其中。

此外,stdout可能已缓冲。 printf()的结果可能无法刷新。如果你调用exit(),它会被刷新,但这对于fork的子端也是不合法的。 (使用_exit()是合适的,但不会刷新打开的流。)实际上,您似乎没有退出子进程,这意味着执行流继续到您的代码的调用者显示,可能会返回到您的其他程序。由于叉子的儿童方面的限制,它可能会卡在那里。

如果你在孩子身上做了类似的事情,你可能会有更多的运气:

const char msg[] = "\nI am the child\n";
write(STDOUT_FILENO, msg, sizeof(msg) - 1);
_exit(0);

最后,我认为您应该将fpid而不是WAIT_ANY传递给waitpid()。您有一个您想要等待的特定子进程。在较大程序的上下文中,您不希望窃取由其他子组件生成的子项终止的通知。而且你总是需要绕过可中断的系统调用,直到它们返回EINTR以外的其他内容。

答案 1 :(得分:0)

仅检查errno是否指示了失败,例如通过系统调用返回-1

代码应如下所示:

pid_t fpid;

if ((fpid = fork()) < 0)
{
    printf("fork: %s\n", strerror(errno));
    exit(-1);
}

if (0 == fpid) // child
{
    printf("\nI am the child\n");
}
else
{
    printf("\nI am the parent\n");

    pid_t wpid;
    while ((wpid = waitpid(WAIT_ANY, NULL, 0)))
    {
        if (-1 == wpid)
        {
            perror("waitpid() failed");
        }
        else if (wpid == fpid)
        {
            /* My child ended, so stop waiting for it. */
            break;
        }
    }
}