免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: xltao
打印 上一主题 下一主题

关于SIGCHLD的不排队,丢弃的问题 [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
11 [报告]
发表于 2006-09-15 17:20 |只看该作者
原帖由 xltao 于 2006-9-15 17:02 发表
愚钝,不太明白flw的意思,既然丢了,是怎么找回来的.执教

根本就不需要找回来!
好比有五个进程,
不妨分别称为 p1 p2 p3 p4 p5,
一开始 p1 结束了,发了一个 SIGCHLD(s1),
这时父进程可能空闲了,于是开始处理这个信号,假设处理的过程中 p2 又结束了,又发了一个 SIGCHLD(s2),
这时候已经有两个信号了(一个正在处理,一个待处理),这时如果 p3 又结束了,那么它发的那个 SIGCHLD(s3) 势必会丢失,
丢失了怎么办?
没关系,因为那个信号处理函数是个循环嘛,
所以 while(waitpid()) 的时候,会把 p1 p2 p3 都处理的。
即使是很不幸,因为十分凑巧的原因,p3 没有被回收,导致变成僵尸进程了,也没关系,
因为还有 p4 p5 嘛,等到 p4 或者 p5 结束的时候,
又会再一次调用 while(waitpid()),到时候虽说这个 while(waitpid()) 是由 p4/p5 引起的,但是它也会一并把 p3 也处理的,因为它是个循环嘛!

如果还搞不懂,你就再看看 waitpid 的 man。

记住一点:
waitpid 和 SIGCHLD 没关系,即使是某个子进程对应的 SIGCHLD 丢失了,只要父进程在任何一个时刻调用了 waitpid,那么这个进程还是可以被回收的。

哎呀呀,简直费劲死了,其实说白了,就是一个“生产者-消费者”问题。
子进程结束的时候,系统“生产”出一个僵尸进程,
同时用 SIGCHLD 通知父进程来“消费”这个僵尸进程,
即使是 SIGCHLD 丢失了,没有来得及消费,
但是只要有一次消费,就会把所有的僵尸进程都处理光光!
(我再说一遍:因为,while(waitpid()) 是个循环嘛!)

[ 本帖最后由 flw 于 2006-9-15 17:24 编辑 ]

论坛徽章:
0
12 [报告]
发表于 2006-09-15 17:22 |只看该作者
这个帖子有可能成为精华。继续讨论

论坛徽章:
0
13 [报告]
发表于 2006-09-15 17:24 |只看该作者
原帖由 xltao 于 2006-9-15 16:59 发表
to susesuse:
不太同意你的看法, 这是个本来就很难重现的问题, 不能因为只举个例子就推出结论.
我想问你当父进程正在执行sigchld的信号处理程序, 内核这时向父进程发送一个sigchld,
因为sigchld是不可靠信号,进 ...


我的意思就是waitpid和信号没关系.

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #include <sys/wait.h>

  7. void child_func()
  8. {
  9.     return;
  10. }

  11. int main(void)
  12. {
  13.     pid_t pid;
  14.     int stat;

  15.     if((pid = fork()) == 0)
  16.     {
  17.         child_func();
  18.         printf("child process %d exit!\n",getpid());
  19.         exit(0);
  20.     }
  21.     else if(pid > 0)
  22.     {
  23.         sleep(5);
  24.         pid = waitpid(-1,&stat,WNOHANG);
  25.         printf("child %d exit!\n",pid);
  26.     }
  27.     else
  28.     {
  29.         printf("fork failed\n");
  30.         exit(-1);
  31.     }

  32.     return 0;
  33. }
复制代码


运行结果:
child process 23507 exit!
child 23507 exit!

这个程序里child信号不早就丢了吗,但子进程不照样被回收了吗?

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
14 [报告]
发表于 2006-09-15 17:32 |只看该作者
susesuse 说的对。
我也给出一个简单的例子。
(下面这个经过改进的例子清晰地说明,SIGCHLD 信号是可以丢失的,但是子进程是不会不回收的)
  1. flw@Sleeper:~$ cat ttt.c
  2. # include <stdio.h>
  3. # include <stdlib.h>
  4. # include <sys/types.h>
  5. # include <sys/wait.h>
  6. # include <unistd.h>

  7. void sigchld_handler( int signo ){
  8.     printf( "我就不在这里回收,看你能怎的?丢吧!丢吧!都丢光都没关系!\n" );
  9.     printf( "我就故意在这里等它三秒钟,让它丢!都丢光才好呢。\n" );
  10.     sleep(3);
  11.     return;
  12. }

  13. int main()
  14. {
  15.     int i;
  16.     pid_t pid;

  17.     signal( SIGCHLD, sigchld_handler );

  18.     for( i=0; i<5; i++ ){
  19.         pid = fork();
  20.         if ( pid == 0 ){
  21.             sleep(2);
  22.             exit(0); // child exit.
  23.         }
  24.         else if ( pid == -1 ){
  25.             perror( "fork" ); // fork failed.
  26.             exit(-1);
  27.         }
  28.     }

  29.     system( "ps -aef | grep ttt" );
  30.     while(waitpid(-1,NULL,0)!=-1);
  31.     system( "ps -aef | grep ttt" );

  32.     return(0);
  33. }
  34. flw@Sleeper:~$ cc -Wall -o ttt ttt.c
  35. flw@Sleeper:~$ ./ttt
  36. flw       4312  3683  0 17:45 pts/1    00:00:00 ./ttt
  37. flw       4313  4312  0 17:45 pts/1    00:00:00 ./ttt
  38. flw       4314  4312  0 17:45 pts/1    00:00:00 ./ttt
  39. flw       4315  4312  0 17:45 pts/1    00:00:00 ./ttt
  40. flw       4316  4312  0 17:45 pts/1    00:00:00 ./ttt
  41. flw       4317  4312  0 17:45 pts/1    00:00:00 ./ttt
  42. flw       4318  4312  0 17:45 pts/1    00:00:00 sh -c ps -aef | grep ttt
  43. 我就不在这里回收,看你能怎的?丢吧!丢吧!都丢光都没关系!
  44. 我就故意在这里等它三秒钟,让它丢!都丢光才好呢。
  45. 我就不在这里回收,看你能怎的?丢吧!丢吧!都丢光都没关系!
  46. 我就故意在这里等它三秒钟,让它丢!都丢光才好呢。
  47. flw       4312  3683  0 17:45 pts/1    00:00:00 ./ttt
  48. flw       4321  4312  0 17:45 pts/1    00:00:00 sh -c ps -aef | grep ttt
  49. 我就不在这里回收,看你能怎的?丢吧!丢吧!都丢光都没关系!
  50. 我就故意在这里等它三秒钟,让它丢!都丢光才好呢。
  51. flw@Sleeper:~$
复制代码

[ 本帖最后由 flw 于 2006-9-15 17:42 编辑 ]

论坛徽章:
0
15 [报告]
发表于 2006-09-15 17:36 |只看该作者
呵呵,版主就是有意思.

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
16 [报告]
发表于 2006-09-15 17:43 |只看该作者
算了,不说废话了,其实就是个很简单的问题。

论坛徽章:
0
17 [报告]
发表于 2006-09-15 17:54 |只看该作者
1。man
2。不能解决, 看看linux内核代码,就知道了,费着这劲干嘛!?

论坛徽章:
0
18 [报告]
发表于 2006-09-15 17:59 |只看该作者
信号与僵尸没什么必然的联系。
你就是压根不理信号,就在那里傻等,一样没有僵尸。

论坛徽章:
0
19 [报告]
发表于 2006-09-15 18:04 |只看该作者
谢谢各位

论坛徽章:
0
20 [报告]
发表于 2006-09-15 18:19 |只看该作者
受益,
while ( (exit_pid=wait(&status)) != -1 ) ctrl_c_op();
这样可否获取所有子进程?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP