请考虑以下fork()
/ SIGCHLD
伪代码.
// main program excerpt for (;;) { if ( is_time_to_make_babies ) { pid = fork(); if (pid == -1) { /* fail */ } else if (pid == 0) { /* child stuff */ print "child started" exit } else { /* parent stuff */ print "parent forked new child ", pid children.add(pid); } } } // SIGCHLD handler sigchld_handler(signo) { while ( (pid = wait(status, WNOHANG)) > 0 ) { print "parent caught SIGCHLD from ", pid children.remove(pid); } }
在上面的例子中,有一个竞争条件." /* child stuff */
"可以在" /* parent stuff */
"开始之前完成,这可能导致孩子的pid在退出后被添加到子列表中,并且永远不会被删除.当应用程序关闭的时候,父母将无休止地等待已经完成的孩子完成.
我能想到的一个解决方案就是有两个列表:started_children
和finished_children
.我将添加到started_children
我现在添加到的相同位置children
.但在信号处理程序中,而不是从children
我添加到删除finished_children
.当应用程序关闭时,父级可以简单地等到started_children
和之间的差异finished_children
为零.
我能想到的另一个可能的解决方案是使用共享内存,例如分享父母的孩子列表并让孩子.add
和.remove
他们自己?但我对此并不太了解.
编辑:另一个可能的解决方案,这是我想到的第一件事,就是简单地添加一个sleep(1)
开头/* child stuff */
但对我来说闻起来很有趣,这就是为什么我把它排除在外.我甚至不确定它是100%修复.
那么,你如何纠正这种竞争条件?如果有一个完善的推荐模式,请告诉我!
谢谢.
最简单的解决方案是在处理pid之后阻止SIGCHLD信号fork()
,sigprocmask()
并在父代码中解除阻塞.
如果孩子死亡,在解锁信号后将调用SIGCHLD的信号处理程序.这是一个关键的部分概念 - 在您的情况下,关键部分在之前fork()
和之后开始children.add()
.