前言:这个帖子主体毫无价值,要是谁不小心看到了,直接跳到后记吧,唯一有用的东西在那里
======================================================
在写一个daemon,其中会fork一些子进程执行命令,一开始我不关心这些命令的返回值,并且有些命令的执行时间会比较长。于是捕获了SIGCHLD,通过while (waitpid (-1, &status, WNOHANG) > 0)来回收进程;
后来需要取得某些命令的返回值,首先尝试system (),命令能够正确执行,可是总返回-1。system()函数比较复杂,屏蔽了几个信号,fork了两次,可能会有副作用。
于是考虑别的方案,最后测试发现,对于不关心返回值的,可以直接fork exec,让signal handler来回收子进程。对于关心返回值的,fork, 子进程exec以后,父进程wait得到返回状态。SIGCHLD不能设置为SIG_IGN,这会导致wait取不到状态。
马上又出现了一个新的问题,对于需要取得返回值得命令,fork之后有一个waitpid,signal handler中也有一个waitpid,子进程退出之后,到底执行了哪个waitpid?这是一种竞争关系,还是有固定的次序?然后google了一下,发现了这个页面
http://www.mail-archive.com/gimp-developer@scam.xcf.berkeley.edu/msg03400.html
Raphael Quinet写了一个测试程序,用来测试waitpid和signal handler哪个先执行,测试发现Linux 和 IRIX 上waitpid 优先于signal handler,而其他大多数的unix系统则是signal handler优先于waitpid。在Linux平台上,刚好符合我的需求。
问题又来了,假如这个程序需要移植到solaris,该怎么做? Interesting…
附Raphael的测试程序:
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int pid;
int sig_pid = 9999;
int sig_status = 9999;
int main_pid = 9999;
int main_status = 9999;
static void
sigchld_handler (int signum)
{
sig_pid = waitpid (pid, &sig_status, WNOHANG);
}
int
main (int argc, char *argv[])
{
int ret;
struct sigaction sa;
struct sigaction osa;
printf ("installing signal handler...\n");
sa.sa_handler = sigchld_handler;
sigfillset (&sa.sa_mask);
sa.sa_flags = SA_RESTART;
ret = sigaction (SIGCHLD, &sa, &osa);
if (ret < 0)
{
printf ("cannot set signal handler, bye!\n");
exit (-1);
}
printf ("forking...\n");
pid = fork ();
if (pid == 0)
{
sleep (1);
_exit (100);
}
printf ("waiting for child %d to exit...\n", pid);
main_pid = waitpid (pid, &main_status, 0);
printf ("child %d has exited\n", pid);
printf (" sig_pid = %d\n", sig_pid);
printf (" sig_status = %d\n", sig_status);
printf (" main_pid = %d\n", main_pid);
printf (" main_status = %d\n", main_status);
if (sig_pid < 0)
{
if (main_pid < 0)
printf ("no child status (fork failed?)\n");
else
printf ("waitpid got the status before sigchld handler was called\n");
}
else
{
if (main_pid < 0)
printf ("sigchld handler was called before waitpid (no status)\n");
else
printf ("you seem to have a very interesting OS...\n");
}
}=========================================================
后记:这个帖子实在太SB了,
要返回值就fork,wait
不要返回值就fork两次,只wait firstchild
连SIGCHLD都不用管
apue 8.6 罚抄100遍啊