这是<Advanced Linux Programming>,第3.4.4章的一个例子 . 程序fork()和exec()是一个子进程 . 我希望父进程能够异步清理子进程(否则子进程将成为一个僵尸进程),而不是等待进程终止 . 可以使用信号SIGCHLD完成 . 通过设置signal_handler,我们可以在子进程结束时完成清理工作 . 代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
int spawn(char *program, char **arg_list){
pid_t child_pid;
child_pid = fork();
if(child_pid == 0){ // it is the child process
execvp(program, arg_list);
fprintf(stderr, "A error occured in execvp\n");
return 0;
}
else{
return child_pid;
}
}
int child_exit_status;
void clean_up_child_process (int signal_number){
int status;
wait(&status);
child_exit_status = status; // restore the exit status in a global variable
printf("Cleaning child process is taken care of by SIGCHLD.\n");
};
int main()
{
/* Handle SIGCHLD by calling clean_up_process; */
struct sigaction sigchld_action;
memset(&sigchld_action, 0, sizeof(sigchld_action));
sigchld_action.sa_handler = &clean_up_child_process;
sigaction(SIGCHLD, &sigchld_action, NULL);
int child_status;
char *arg_list[] = { //deprecated conversion from string constant to char*
"ls",
"-la",
".",
NULL
};
spawn("ls", arg_list);
return 0;
}
但是,当我在终端中运行程序时,父进程永远不会结束 . 而且它似乎没有执行函数clean_up_child_process(因为它不打印出“清洁子进程由SIGCHLD处理 . ”) . 这段代码有什么问题?
3 回答
我正在使用Mac,所以我的答案可能不太相关,但仍然如此 . 我没有任何选项编译,所以可执行文件名是
a.out
.我对控制台有相同的经验(这个过程没有't seem to terminate), but I noticed that it'只是终端故障,因为你实际上只需按Enter键,你的命令行就会回来,实际上从其他终端窗口执行的
ps
不显示a.out
,也不是ls
它推出了 .此外,如果我运行
./a.out >/dev/null
它立即完成 .所以上述的观点是,一切都实际终止,只是终端由于某种原因冻结 .
接下来,为什么它永远不会打印
Cleaning child process is taken care of by SIGCHLD.
. 仅仅因为父进程在子进程之前终止 .SIGCHLD
信号无法传递到已终止的进程,因此永远不会调用处理程序 .在书中,它表示父进程继续做其他一些事情,如果确实如此,那么一切正常,例如,如果你在
spawn()
之后添加sleep(1)
.从
fork()
返回子pid后,父进程立即从main()
返回,它永远不会有机会等待子进程终止 .适用于GNU / Linux用户
我已经读过这本书了 . 虽然这本书谈到这个机制是:
引自本书3.4.4第59页:
但它只是说你可以使用
sigaction
来处理这种情况 .以下是如何以这种方式处理进程的完整示例 .
首先为什么我们使用这种机制?好吧,因为我们不希望将所有进程同步在一起 .
real example
想象一下,你有10个
.mp4
文件,你想将它们转换为.mp3
文件 . 好吧,我 junior 用户这样做:并重复此命令10次 . 更高的用户这样做:
这一次,这个命令 pipes 每行10个
mp4
个文件,每个 one-by-one 到xargs
然后将它们逐个转换为mp3
.但我 senior 用户这样做:
这意味着如果我有10个文件,请创建 10 processes 并同时运行它们 . 并且有 BIG 不同 . 在前两个命令中,我们只有一个进程;它被创建然后终止然后继续到另一个 . 但是在
-P 0
选项的帮助下,我们同时创建了10个进程,实际上正在运行10个ffmpeg
命令 .现在 cleaning up children asynchronously 的目的变得更清洁了 . 事实上我们想运行一些 new processes 但是这些进程的顺序以及它们的退出状态对我们来说无关紧要 . 通过这种方式,我们可以尽可能快地运行它们并减少时间 .
首先,您可以查看
man sigaction
以获取您想要的更多详细信息 .第二次看到这个信号号码:
sample code
目标:使用
SIGCHLD
清理子进程这是示例代码的作用:
创建5个子进程
然后进入内部循环并暂停以接收信号 . 见
man pause
然后当子进程终止时,父进程唤醒并调用
signal_handler
函数继续到最后一个:
sleep 9
输出:(17表示
SIGCHLD
)当你运行这个示例代码时,在另一个_477498上试试这个:
正如你所看到的
a.out
进程有5个孩子 . 它们同时运行 . 然后 whenever 每个终止, kernel 将信号SIGCHLD
发送到它们的父节点:a.out
NOTE
如果我们不使用
pause
或任何机制使 parent 为其子节点wait
,那么我们将放弃创建的进程并且 upstart (= onUbuntu
或init
)成为它们的父节点 . 您可以尝试删除pause()