我在posix过程的主题上遇到了问题,我无法解决。
我有一个流程,它会分叉几个孩子(流程树可能很复杂,不仅仅是一个级别)。它还跟踪活跃的儿童的PID。在某些时候,父母会收到一个信号(SIGINT,比方说)。
在SIGINT的信号处理程序中,它遍历子进程列表并向它们发送相同的信号以防止僵尸。现在,问题在于
父级和子级具有相同的信号处理程序,因为它在分叉之前已安装。 这是一个伪代码。
signal_handler( signal )
foreach child in children
kill( child, signal )
waitpid( child, status )
// Releasing system resources, etc.
clean_up()
// Restore signal handlers.
set_signal_handlers_to_default()
// Send back the expected "I exited after XY signal" to the parent by
// executing the default signal handler again.
kill( getpid(), signal )
通过此实现,执行将在waitpid上停止。如果我删除了waitpid,孩子们就会继续运行。
我的猜测是,除非信号处理程序已经结束,否则从它发送的信号不会发送给孩子。但是,如果我省略等待,他们为什么不派遣?
提前多多感谢!
答案 0 :(得分:6)
您描述的内容应该有效,确实如此,使用以下测试用例:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#define NCHILDREN 3
pid_t child [NCHILDREN];
struct sigaction sa, old;
static void
handler (int ignore)
{
int i;
/* Kill the children. */
for (i = 0; i < NCHILDREN; ++i)
{
if (child [i] > 0)
{
kill (child [i], SIGUSR1);
waitpid (child [i], 0, 0);
}
}
/* Restore the default handler. */
sigaction (SIGUSR1, &old, 0);
/* Kill self. */
kill (getpid (), SIGUSR1);
}
int
main ()
{
int i;
/* Install the signal handler. */
sa.sa_handler = handler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
sigaction (SIGUSR1, &sa, &old);
/* Spawn the children. */
for (i = 0; i < NCHILDREN; ++i)
{
if ((child [i] = fork ()) == 0)
{
/* Each of the children: clear the array, wait for a signal
and exit. */
while (i >= 0)
child [i--] = -1;
pause ();
return 0;
}
}
/* Wait to be interrupted by a signal. */
pause ();
return 0;
}
如果您看到父项挂在waitpid
,则表示该孩子尚未退出。尝试使用调试器附加以查看子项被阻止的位置,或者更轻松地使用strace(1)
运行程序。你如何清理你的pid阵列?确保孩子没有尝试使用pid参数为&lt; = 0的呼叫waitpid
。确保孩子没有阻止或忽略信号。