2011-12-30 112 views
9

我正在处理使用fork()和exec来创建子进程的服务器代码。当fork()成功并且在CHILD信号被捕获时被清除,该孩子的PID被注册。KILL信号是否立即退出进程?

如果服务器需要停止,所有的程序都会被终止,最终会产生一个KILL信号。现在,这是通过遍历所有已注册的PID并等待CHILD信号处理程序去除PID来工作的。如果子程序没有正确退出,这将失败。因此,我想使用killwaitpid结合使用,以确保PID列表被清除并记录,否则会执行其他一些操作。

考虑下一个代码样品:

kill(pid, SIGKILL); 
waitpid(pid, NULL, WNOHANG); 

摘自waitpid(2)

waitpid函数():成功时返回其状态已经改变子的进程ID;如果WNOHANG被指定并且存在一个或多个由pid指定的子(ren) ,但尚未更改状态,则返回0。出错时,返回-1。

pid给出的过程总是在下一个函数启动之前消失吗?在上述情况下,waitpid总是会返回-1

+2

KILL信号相当残酷,为什么不是INT或HUP?还有,“kill”系统调用的返回码是什么? “ – fge 2011-12-30 12:03:21

+0

”等待CHILD信号处理程序...“ - SIGKILL没有信号处理程序,你知道吗?除了SIGSTOP和SIGKILL以外,所有的信号都会执行'sigaction'(例如调用处理程序)或缺省值。 SIGSTOP刚刚停止,SIGKILL只是杀死了这个进程。总是。没有处理或有条件的。 (例外情况是'kill'系统​​调用失败,因为你没有足够的权限。) – Damon 2011-12-30 12:15:47

+0

@Damon:目标进程不能忽略'SIGKILL',这就对了。但那不是问题/问题。源进程的'kill(2)'系统调用可以在信号在目标进程的上下文中被内核评估之前返回。 'kill(2)'基本上是一个非常简单的异步通信,必须作为所有含义来对待。 – 2011-12-30 12:22:07

回答

8

在下一个函数启动之前,pid给出的过程是否总是消失?

没有保证。在一个多处理器上,你的进程可能在CPU 0上,而在内核中对于死亡进程的清理发生在CPU 1上。这是一个经典的竞争条件。即使在单数处理器上也无法保证。

在上述情况下,waitpid总是返回-1吗?

由于它是一种竞争条件 - 在大多数情况下它可能会。但是没有保证。


既然你不感兴趣的状态,这semicode可能是你的情况更为合适:

// 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; 
+0

感谢您的解释,我将无法使用建议的代码,因为SIGCHILD处理程序会从pidlist中删除项目。这让我可以选择:检查进程是否正在运行,如果没有,请删除,否则杀死。 – Lekensteyn 2011-12-30 15:28:29

+0

只需删除'WNOHANG'标志,您的代码将按预期工作。 – 2011-12-30 17:12:49

+0

@Lekensteyn:如果已经有一个更新列表的SIGCHLD处理程序,那么这个处理程序可以调用'waitpid'来移除僵尸进程。那么'while'循环只需要等待a)所有进程都已经死亡或被埋没了,或者b)为了安全起见,一些超时。 – 2011-12-30 18:03:19

4

KILL信号处理程序将在杀死进程CPU时间运行。这可能远远晚于您的waitpid呼叫,特别是在加载的系统上,因此waitpid可以很好地返回0.