如何在后台执行僵尸进程后避免僵尸进程

时间:2010-05-21 10:01:33

标签: c shell background

我们在C中编写类似shell的bash,但我们遇到了后台进程的问题。 事情是,当没有&时,父亲等待子进程,我们为SIGCHLD做了一个signal_handler,里面有一个等待。

我们要避免的主要问题是:signal_handler始终执行(使用后台进程和前台进程),因此如果signal_handler在父进程之前捕获SIGCHLD,则父进程等待没有子进程等待,所以它返回一个错误。

我们依赖于他们之前执行的人,如果没有& signal_handler wait不会在父亲之前收集孩子。

任何帮助都是至关重要的。非常感谢。

1 个答案:

答案 0 :(得分:1)

我的问题对我来说有点不清楚,但我会提到一些我曾考虑过做类似情况的事情。

创建流程时,您可以暂时阻止SIGCHLD并将子流程的记录(以及如何处理)放入表中。

child_table_node_t * node = malloc(sizeof(child_table_node_t) );
// err check that
child_table_node_init(node, type_of_child_stuff);

sigset_t old, set;

sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, &old);
pid_t pid = fork();
if (pid > 0) {
   node->pid = pid;
   add_to_table(alive_children, node);
   sigprocmask(SIG_SETMASK, &old, NULL);
   // other stuff
} else {
   sigprocmask(SIG_SETMASK, &old, NULL);
   if (!pid) {
       // do child stuff
   } else {
       // do parent with no child stuff
   }
}

然后你的handle_sigchild可以查找表中死亡(或停止或其他)的孩子并为他们做点什么。我建议将它们从alive_children表中删除,并将它们放入信号处理程序中的dead_children表中,以便应用程序可以更轻松地处理它们并释放它们的内存。如果你想跟上孩子被拦截以及死亡的话,那么b / c将会变得更加复杂,你不想将它们从活着的桌子上移除。在非信号代码中遍历表以定位已更改的节点可能更容易。如果是这种情况,您可以在不阻止信号的情况下执行此操作,除非您添加或删除节点。

然后,您的应用程序可以根据存储在该进程的表节点中的数据执行特定于死亡的子进程的操作。如果孩子在前台,则死亡(或停止动作)将退出代码存储到退出代码变量中,并再次从终端或脚本开始接受命令。如果新死的孩子是后台进程,那么您只需记录其退出代码并在下次打印命令提示符之前将其报告给终端(如果您处于交互模式)。