使用waipid的时候遇到了一个奇怪的问题,将情况简化后描述一下。
有关waitpid的基本介绍参见这里一下:http://www.cnblogs.com/mickole/p/3187770.html
示例代码如下所示。主进程会处理SIGCHLD信号,处理过程是等待子进程结束,如果子进程正常退出,打印捕获到了SIGCHLD信号,否则打印错误码。让主进程后面sleep 3s是为了防止主进程先于子进程退出,从而没办法响应子进程的退出信号。
测试正常fork的情况
注释掉capture2和test system部分,使用capture1和test fork。
正常的情况输出
this is parent.
this is child.
capture SIGCHLD1
视乎执行顺序,前两句有可能顺序反过来,即先执行子进程,后执行主进程后面的部分
测试system函数的情况
注释掉capture2和test fork部分,使用capture1和test system部分。
输出如下
a.out waitpid.c
SigChildFunc error! errno=10
可见这里waitpid出错了,没得到子进程的退出状态,其中errno 10表示No child processes(errno定义见http://baike.baidu.com/view/3485007.htm),不过并不妨碍system正确执行命令。
原因在于system函数内部会经历fork()->exec()->waitpid()三个阶段,而我们的主函数中有处理SIGCHLD信号,里面还有waitpid操作。system本身的waitpid操作已经为子进程收尸过了,后面那个就会找不到子进程。处理的一种方式可以参见http://www.verydemo.com/demo_c167_i3191.html中的故事,我使用了另一种方式:即只waitpid我fork出的子进程,别的忽略掉,即waitpid的第一个参数不传-1,而是child_pid。
测试连续两次waitpid的情况
注释掉test system,使用capture1、capture2和test fork部分。
输出如下
this is parent.
this is child.
capture SIGCHLD1
SigChildFunc error! errno=10
同样得到了一次errno=10的错误。这说明不能连续尝试2次waitpid。
题外话
在lua中,os.execute等同于c中的system函数,因此如果主进程执行lua逻辑,同时在处理SIGCHLD信号时使用waitpid捕获子进程退出状态,那么lua中使用os.execute时需要注意这一点。
1 #include <sys/wait.h> 2 #include <sys/types.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include "errno.h" 7 8 void SigChildFunc() 9 { 10 pid_t pid; 11 int status; 12 13 // capture1 begin 14 pid = waitpid(-1, &status, WNOHANG); 15 if(pid > 0) 16 { 17 printf("capture SIGCHLD1\n"); 18 } 19 else 20 { 21 printf("SigChildFunc error! errno=%d\n", errno); 22 } 23 // capture1 end 24 25 // capture2 begin 26 // pid = waitpid(-1, &status, WNOHANG); 27 // if(pid > 0) 28 // { 29 // printf("capture SIGCHLD2\n"); 30 // } 31 // else 32 // { 33 // printf("SigChildFunc error! errno=%d\n", errno); 34 // } 35 // capture2 end 36 } 37 38 void SignalCB(int Signal) 39 { 40 switch(Signal) 41 { 42 case SIGCHLD: 43 SigChildFunc(); 44 break; 45 default: 46 break; 47 } 48 } 49 50 int main() 51 { 52 signal(SIGCHLD, SignalCB); 53 54 // test system begin 55 system("ls"); 56 // test system end 57 58 // test fork begin 59 // pid_t pid = fork(); 60 // if(pid < 0) 61 // { 62 // printf("fork error! errno=%d\n", errno); 63 // } 64 // else if(pid == 0) 65 // { 66 // printf("this is child.\n"); 67 // exit(0); 68 // } 69 // 70 // printf("this is parent.\n"); 71 // sleep(3); 72 // test fork end 73 74 return 0; 75 }