免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 15043 | 回复: 12
打印 上一主题 下一主题

子进程退出父进程没有收到SIGCHLD? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-02-17 10:40 |只看该作者 |倒序浏览
最近看多进程编程,写了个超BT的Demo,代码如下:

     6 void child_end(int signum)
      7 {
      8         int child_status;
      9         int pid;
     10         pid = wait(&child_status);
     11         printf("child:%d exit status: %d\n", pid, child_status);
     12 }
     13
     14 int main()
     15 {
     16         int child_pid;
     17         if ( signal(SIGCHLD, child_end) == SIG_ERR )
     18         {
     19                 return 1;
     20         }
     21         for ( int i = 0; i < 10; i++ )
     22         {
     23                 child_pid = fork();
     24                 if ( child_pid == -1 )
     25                 {
     26                         printf("fork error \n");
     27                         return 2;
     28                 }
     29                 else if ( child_pid == 0 )//in child process
     30                 {
     31                         printf("hello word %d\n", getpid() );
     32                         exit(1);
     33                 }
     34         }
     35         printf("in parent process %d\n", getpid() );
     36         for(int i = 1; i < 10; i++)
     37         {
     38                 sleep(1);
     39         }
     40         return 0;
     41 }

程序一开始就创建了10个子进程,输出了10个“hello word XXXX”,可见创建成功,但是只输出了3句“child:%d exit status: %d”
信息,为什么?父进程退出前ps可以看到N个僵死进程。有的子进程结束了,但是SIGCHLD信号没有被父进程捕捉到?
还有为什么我子进程exit(1)的话父进程得到的child_status就是256,exit(2)的话就是512???exit(10)得到的child_status就是2560???

论坛徽章:
0
2 [报告]
发表于 2006-02-17 12:59 |只看该作者
原帖由 nightfall 于 2006-2-17 10:40 发表
程序一开始就创建了10个子进程,输出了10个“hello word XXXX”,可见创建成功,但是只输出了3句“child:%d exit status: %d”
信息,为什么?父进程退出前ps可以看到N个僵死进程。有的子进程结束了,但是SIGCHLD信号没有被父进程捕捉到?
还有为什么我子进程exit(1)的话父进程得到的child_status就是256,exit(2)的话就是512???exit(10)得到的child_status就是2560??? ...



只输出了3句“child:%d exit status: %d”的原因应该和当时进程的信号处理能力有关,
你不妨多执行几次你的程序,你会发现打印出来的上述语句的数目是不定的,而且不时就会
有全部都打印出来的情况。

至于你所打印出来的child_status的值是256、512、。。。,是因为这个“int”型的变量
并不完全是你传给exit的入参。你把child_status用十六进制打印出来就清楚了。系统提供了
一个宏,使你可以从child_status中得到传给exit的入参,这个宏实际上就是把child_status
除以256。

/usr/src/sys/sys/wait.h:
  1. #define        WEXITSTATUS(x)        (_W_INT(x) >> 8)
复制代码

论坛徽章:
0
3 [报告]
发表于 2006-02-17 15:00 |只看该作者
只输出了3句“child:%d exit status: %d”的原因应该和当时进程的信号处理能力有关,
你不妨多执行几次你的程序,你会发现打印出来的上述语句的数目是不定的,而且不时就会
有全部都打印出来的情况。
--------------------------------------------------------------------------------------------------
确实是这样,但是我要怎样才可以wait到所有的子进程呢?

呵呵,我也知道除以256就可以得到返回值,只是不知道这个256用来干嘛的^_^

谢谢!

论坛徽章:
0
4 [报告]
发表于 2006-02-17 15:29 |只看该作者
原帖由 nightfall 于 2006-2-17 15:00 发表
确实是这样,但是我要怎样才可以wait到所有的子进程呢?

呵呵,我也知道除以256就可以得到返回值,只是不知道这个256用来干嘛的^_^


对于第一个问题我现在也不是很确定,只能先承认系统中毕竟还有“不确定”因素了,

第二个问题,只能说系统是这么放的,所以你也只能这么取,否则它也不会专门为此定义一个移位宏了。
至于wait所写的那个int类型的数值的低8位拿来做什么了我现在也不清楚,回去查查书先!

论坛徽章:
0
5 [报告]
发表于 2006-02-17 16:17 |只看该作者
信号系统仍然不是“可靠”的。如果同一时间同一进程收到同一个信号,原先的处理可能会被中断。

以楼主的程序为例,只要加一个停顿,即可获得所有SIGCHLD信号。

     29                 else if ( child_pid == 0 )//in child process
     30                 {
     31                         printf("hello word %d\n", getpid() );
                                  sleep(i);//不同的子进程睡眠不同的时间后再退出,让父进程在不同的时间收到SIGCHLD信号。
     32                         exit(1);
     33                 }

论坛徽章:
0
6 [报告]
发表于 2006-02-17 16:28 |只看该作者
也可修改signal处理函数。
如果作如下的修改,可以保证在90%的情况下都能得到10个SIGCHLD。但是不能保证100%。我做大约20次实验,有一次不是。
int flag=0;

     6 void child_end(int signum)
      7 {
                 if(flag!=0)sleep(1);
      8         int child_status;
      9         int pid;
                 flag=1;
     10         pid = wait(&child_status);
     11         printf("child:%d exit status: %d\n", pid, child_status);
                  flag=0;
     12 }

论坛徽章:
0
7 [报告]
发表于 2006-02-17 16:40 |只看该作者
用楼上的方法确实可以捕获所有的信号,但是除此之外还有没有办法,毕竟让一个进程完成了工作还sleep挺无聊的
在现实的工程中要怎样才能保证可以wait到所有的子进程,即使他们同时终止。

谢谢两位了哈

论坛徽章:
0
8 [报告]
发表于 2006-02-17 16:43 |只看该作者
根本原因在于,绝大多数函数是不可“重入”的。

比如例子中的printf函数(标准IO为库的很多函数实现都是不可重入的)。
如果不使用PRINTF函数,而只是进行计数,结果也会证实父进程获得了所有的SIGCHLD信号(这里的表述有些问题,实际上只进行计数,会修改全局变量或静态变量,使得函数不可重入,从而不会100%得到所有的SIGCHLD信号)

APUE例举了一些可重入的函数。

[ 本帖最后由 assiss 于 2006-2-17 19:39 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2006-02-17 16:47 |只看该作者
原帖由 nightfall 于 2006-2-17 16:40 发表
用楼上的方法确实可以捕获所有的信号,但是除此之外还有没有办法,毕竟让一个进程完成了工作还sleep挺无聊的
在现实的工程中要怎样才能保证可以wait到所有的子进程,即使他们同时终止。

谢谢两位了哈


现实的工程中,一定不能在SIGNAL处理函数中使用不可重入的函数。
可以使用的库函数可以参考APUE中的列表,如果使用自己的函数,一定要仔细设计,确保被中断后还可重入执行。

论坛徽章:
0
10 [报告]
发表于 2006-02-17 17:02 |只看该作者
原帖由 assiss 于 2006-2-17 16:43 发表
根本原因在于,绝大多数函数是不可“重入”的。

比如例子中的printf函数(标准IO为库的很多函数实现都是不可重入的)。
如果不使用PRINTF函数,而只是进行计数,结果也会证实父进程获得了所有的SIGCHLD信号。 ...


这个让人信服!

另外有个无关的事情,在SIGCHLD处理函数里面好像一般更多用waitpid而不是wait
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP