2010-05-21 100 views
2

我们在C中编写一个像shell一样的bash,但是后台进程有问题。 事情是,当没有&时,父亲等待子进程,我们为SIGCHLD做了一个signal_handler,它里面有一个等待。如何在后台执行后避免僵尸进程

我们想要避免的主要问题是:signal_handler总是执行(有背景和前台进程),所以如果signal_handler在父进程之前捕获到SIGCHLD,那么父亲的等待没有孩子可以等待,所以它返回一个错误。

我们取决于他们之前执行过谁,我们希望如果没有&,那么signal_handler等待在父亲执行之前不会收集子女。

任何帮助都是非常重要的。提前致谢。

+0

正在做作业吗? – fortran 2010-05-21 10:22:27

+0

设置“父亲”进程除了检查已终止的孩子之外什么也不做。从而减少了一个crach的可能性。你应该在cild过程中做所有的工作。 – eaanon01 2010-05-21 10:23:26

回答

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,你不会希望从活着的表中删除它们。在非信号代码中遍历表可能更容易找到更改的节点。如果是这种情况,您可以在不添加或删除节点的情况下阻止信号。

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

+1

您的建议非常有用。我们最终创建了一个数组来存储后台进程的PID,以便只等待signal_handler中的这些PID。 我们真的很感谢你的回答;)。 – PID 2010-05-22 10:50:38

+0

我很高兴这很有帮助。祝你的项目好运:-) – nategoose 2010-05-23 19:37:46