我有这个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吗?
答案 0 :(得分:1)
stdio缓冲区的状态包含在进程的内存空间中。如果在fork时缓冲区不为空,则父节点和子节点都有一个信息副本,表示_exit
在stdout缓冲区中,等待刷新。
他们最终都会冲洗它。
您可以通过在子进程中调用exit
而不是exit
来避免这种情况。 {{1}}通常是一个糟糕的主意,当你在一个创建成功的exec以来没有完成的过程中。
答案 1 :(得分:0)
问题是你的调试输出。在异步信号处理程序中调用printf是未定义的行为。在信号处理程序中,只有一小部分功能可以确保安全。
如果删除它,您将看到信号处理程序外部的一个从未出现意外行为。