我们正在用 C 编写一个类似 bash 的 shell,但我们在后台进程方面遇到了问题。 问题是当没有 & 时,父亲会等待子进程,我们为 SIGCHLD 创建了一个 signal_handler,里面有一个等待。
我们要避免的主要问题是:signal_handler一直执行(有后台和前台进程),所以如果signal_handler在父进程之前捕获到SIGCHLD,那么父亲的等待没有 child 等待,所以它返回一个错误。
我们取决于他们中的谁在之前执行,我们希望如果没有并且 signal_handler wait 不会在父亲之前收集 child 。
任何帮助都至关重要。非常感谢。
最佳答案
你的问题对我来说有点不清楚,但我会提到一些我在类似情况下考虑过的事情。
当您创建一个进程时,您可以暂时阻止 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
然后可以在表中查找死亡(或停止或其他)的 child 并为他们做一些事情。我建议将它们从 alive_children
表中移除,并在它们死亡时将它们放入信号处理程序中的 dead_children
表中,以便您的应用程序可以更轻松地处理它们并释放它们的内存。如果您想跟上 child 被停止和死亡的情况,那么这将变得更加复杂 b/c 您不想将它们从事件表中删除。在非信号代码中遍历表以定位更改的节点可能更容易。如果是这种情况,您可以在不阻塞信号的情况下执行此操作,除非您添加或删除了节点。
然后,您的应用程序可以根据存储在该进程的表节点中的数据,针对已死亡的 child 执行特定操作。如果 child 在前台,那么它的死亡(或停止 Action )将是将退出代码存储到退出代码变量中,并再次开始从终端或脚本接收命令。如果新死的 child 是后台进程,那么您只需记录它的退出代码并在下次打印命令提示符(如果您处于交互模式下)之前将其报告给终端。
关于c - 如何在后台执行僵尸进程后避免它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2881119/