我应该担心进程组中进程接收信号的顺序吗?

5

我希望通过向进程组内的进程发送SIGTERM信号来终止该进程组。这可以通过kill命令完成,但我找到的手册提供的细节很少,不清楚具体的工作原理:

   int kill(pid_t pid, int sig);
   ...
   If pid is less than -1, then sig is sent to every  process  in
   the process group whose ID is -pid.

然而,信号将按照什么顺序发送到组成员进程中?想象一下以下情况:在主进程和组内从属进程之间设置了一个管道。如果在处理过程中杀死从属进程kill(-pid),而主进程还没有被杀死,主进程可能会报告这是一种内部故障(收到子进程死亡的通知)。然而,我希望所有进程都能理解这样的终止是由于他们的进程组外部原因造成的。

我该如何避免这种混乱?我应该做些比单纯的kill(-pid,SIGTERM)更多的事情吗?或者这是由操作系统的底层属性解决的,而我不知道吗?

请注意,我不能修改组内进程的代码!

4个回答

5
尝试将其作为三个步骤来完成:
kill(-pid, SIGSTOP);
kill(-pid, SIGTERM);
kill(-pid, SIGCONT);

第一个SIGSTOP信号会将所有进程置于停止状态,因为它们无法捕获此信号,所以整个进程组都将停止。
SIGTERM信号将排队等待该进程处理,但我不认为它会被传送,因为进程已经停止(这是我从记忆中得出的结论,目前我无法找到参考资料,但我相信这是正确的)。
SIGCONT信号将重新启动进程,使SIGTERM信号可以被传送。如果从属进程先接收到SIGCONT信号,则主进程可能仍处于停止状态,因此它将无法注意到从属进程的离开。当主进程接收到SIGCONT信号时,它将随后接收到SIGTERM信号,终止它。
我不知道这是否真正有效,而且实际上所有信号何时被传递(包括向主进程发送的SIGCHLD信号)可能是依赖于具体实现的,但值得一试。

1
是的,这个解决方案就是我目前实现的。我检查了我的系统上的SIGTERM处理程序确实不会被调用,直到进程由于SIGCONT唤醒。我的实验还表明,所有正确的SIGCHLD信号都会传递给控制进程:在子进程停止、恢复和终止时,我们发送信号。 - P Shved
1
检查 ps 输出或 /proc/<pid>/stat 来检查进程状态,其中在 ps 输出中使用 T 表示停止状态(根据 man 手册)。 - mvds

1

我的理解是,您不能依赖于任何特定的信号传递顺序。

如果您只向主进程发送TERM信号,然后让主进程杀死其子进程,您就可以避免这个问题。


我不能让“主”做任何事情。假设它的来源不可用。实际上,这就是为什么我的问题出现的原因。 :-) - P Shved
@Pavel Shved - 这真的是一个编程问题吗?据我所知,Marius是正确的,但在ServerFault上询问可能是值得的。系统管理员类型喜欢这些问题。 :) - Duck
@Duck,这确实是一个编程问题,但也许Server Fault的用户更了解这个问题,感谢您提供的指引。 - P Shved

1
即使所有不同版本的UNIX都承诺按特定顺序传递信号,调度程序仍可能决定在父代码之前运行关键子进程代码。
即使是您的STOP/TERM/CONT序列也会受到影响。
恐怕您可能需要更复杂的东西。也许子进程可以捕获SIGTERM,然后循环直到其父进程退出,然后再退出自己?如果这样做,请确保添加超时。

我无法更改我终止的进程的代码。抱歉,问题已经修改。 - P Shved

0

未经测试:使用共享内存并放置某种“我们正在死亡”的信号量,在将 I/O 错误视为真正错误之前,可以检查该信号量。mmap() 使用 MAP_ANONYMOUS|MAP_SHARED,并确保它能生存于你的进程的 fork()。

哦,一定要使用 volatile 关键字,否则你的信号量会被优化掉。


再说一遍,我无法修改任何进程。如果可以的话,生活会容易得多... - P Shved

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接