fork为这个c程序生成错误的输出?

时间:2017-04-25 01:56:56

标签: c linux gcc fork

我有这个c代码

/* SIGCHLD handler. */
static void sigchld_hdl (int sig)
{
    /* Wait for all dead processes.
     * We use a non-blocking call to be sure this signal handler will not
     * block if a child was cleaned up in another part of the program. */
     //printf("Inside handler:  \n");
    while (waitpid(-1, NULL, WNOHANG) > 0) {
        printf("reaped\n");
    }
     //printf("Outside handler:  \n");

}

int main (int argc, char *argv[])
{
    struct sigaction act;
    int i;

    memset (&act, 0, sizeof(act));
    act.sa_handler = sigchld_hdl;

    if (sigaction(SIGCHLD, &act, 0)) {
        perror ("sigaction");
        return 1;
    }

    /* Make some children. */
    for (i = 0; i < 5; i++) {
        switch (fork()) {
            case -1:
                perror ("fork");
                return 1;
            case 0:
                 exit(0);
                return 0;
            default:
                //printf("inside parent\n");
                printf("Created child %d\n", i);

        }
    }

    /* Wait until we get a sleep() call that is not interrupted by a signal. */
    while (sleep(1)) {
        printf("inside parent while loop\n");
    }

    return 0;
}

我正在调用fork 5次,所以我期望共有5个子进程和1个父进程。当我运行此代码时,我得到此输出

Created child 0
Created child 1
reaped
reaped
Created child 2
Created child 3
Created child 3
reaped
reaped
Created child 4
reaped
inside parent while loop

我无法弄清楚为什么我会看到child3两次。关于i,不应该有任何重复,因为我在每次迭代中递增。

有人可以解释我为什么两次看到child3吗?

2 个答案:

答案 0 :(得分:1)

stdio缓冲区的状态包含在进程的内存空间中。如果在fork时缓冲区不为空,则父节点和子节点都有一个信息副本,表示_exit在stdout缓冲区中,等待刷新。

他们最终都会冲洗它。

您可以通过在子进程中调用exit而不是exit来避免这种情况。 {{1}}通常是一个糟糕的主意,当你在一个创建成功的exec以来没有完成的过程中。

答案 1 :(得分:0)

问题是你的调试输出。在异步信号处理程序中调用printf是未定义的行为。在信号处理程序中,只有一小部分功能可以确保安全。

如果删除它,您将看到信号处理程序外部的一个从未出现意外行为。