我正在研究使用fork()
和exec创建子进程的服务器代码。在fork()
成功时注册子项的PID,并在捕获CHILD
信号时进行清理。
如果服务器需要停止,所有程序都会被终止,最终会有一个KILL信号。现在,这通过迭代所有已注册的PID并等待CHILD信号处理程序移除PID来工作。如果子程序没有正确退出,这将失败。因此,我希望将kill
与waitpid
结合使用,以确保清除PID列表并记录并执行其他一些操作。
考虑下一个代码示例:
kill(pid, SIGKILL);
waitpid(pid, NULL, WNOHANG);
摘录自waitpid(2)
:
waitpid():成功时,返回状态已更改的子进程ID;如果指定了WNOHANG且一个或多个孩子 由pid指定存在,但尚未更改状态,则返回0。出错时,返回-1。
pid
给出的过程是否总是在下一个函数启动之前消失?在上述情况下,waitpid
总是会返回-1
吗?
答案 0 :(得分:9)
在下一个函数开始之前,pid给出的进程是否总是消失?
无法保证。在多处理器上,您的进程可能在CPU 0上,而内核中针对被杀死进程的清理在CPU 1上进行。这是一个经典的竞争条件。即使在单一处理器上,也无法保证。
在上述情况下,waitpid是否总是返回-1?
因为这是一种竞争条件 - 在大多数情况下它可能会。但是没有保证。
由于您对状态不感兴趣,因此在您的情况下,此半字节可能更合适:
// kill all childs
foreach(pid from pidlist)
kill(pid, SIGKILL);
// gather results - remove zombies
while( not_empty(pidlist) )
pid = waitpid(-1, NULL, WNOHANG);
if( pid > 0 )
remove_list_item(pidlist, pid);
else if( pid == 0 )
sleep(1);
else
break;
答案 1 :(得分:4)
KILL
信号处理程序将在被杀死的进程CPU时间内运行。这可能比您的waitpid
调用晚得多,尤其是在加载的系统上,因此waitpid
可以很好地返回0。