Chinaunix

标题: UNIX或Linux系统对信号是否有排队机制 [打印本页]

作者: Kevinkw    时间: 2005-04-15 15:24
标题: UNIX或Linux系统对信号是否有排队机制
如果说父进程fork了很多子进程并处理SIGCHLD信号已获得子进程统计信息
但是在同一时间有很多子进程结束,这时似乎有很多信号SIGCHLD几乎同时到达
如果我的SIGCHLD信号需要是不可重入的(因为要操作共享资源),如果调用sigprocmask暂时屏蔽SIGCHLD的话,在APUE书上好象讲系统只能向进程传送一次被屏蔽信号
大多数UNIX系统不排队信号,如何判断本系统是否支持信号排队?
谁有比较好的解决方案啊,多谢
作者: win_hate    时间: 2005-04-16 09:25
标题: UNIX或Linux系统对信号是否有排队机制
没见过排队的。

用 while (waitpid (-1, NULL,  WNOHANG) >;0) 可以吗?
作者: Kevinkw    时间: 2005-04-27 20:34
标题: UNIX或Linux系统对信号是否有排队机制
我现在就是用的while (waitpid (-1, NULL,  WNOHANG) >;0),似乎是能解决问题,这样似乎验证了信号是排队的,不然怎么可以用while这样一个一个的捕获?
但是程序执行的时候有不规律的出现僵尸的现象,似乎还是可能丢掉信号的
作者: Kevinkw    时间: 2005-04-27 20:37
标题: UNIX或Linux系统对信号是否有排队机制
还有一个问题,程序在SIGCHLD信号处理函数中执行时又获得了SIGCHLD,那么是否会导致这个函数重入?
如果需要在函数中处理临界资源怎么办?
作者: lisp    时间: 2005-04-28 09:43
标题: UNIX或Linux系统对信号是否有排队机制
〉〉程序在SIGCHLD信号处理函数中执行时又获得了SIGCHLD,那么是否会导致这个函数重入?
不会,在信号处理程序中会屏蔽当前信号,导致递交延迟

〉〉这样似乎验证了信号是排队的
LINUX不会对普通信号排队。子进程的结束是串行的,如果SIGCHLD信号处理程序的执行时间不是太长的话,父进程应该来得及清理子进程。但如果子进程退出频率过高,可能会导致SIGCHLD信号丢失,这就会产生你提到的不规则的僵死进程。
作者: loc1129    时间: 2006-04-07 20:39
>>"子进程的结束是串行的,如果SIGCHLD信号处理程序的执行时间不是太长的话,父进程应该来得及清理子进程。但如果子进程退出频率过高,可能会导致SIGCHLD信号丢失,这就会产生你提到的不规则的僵死进程。"
      问:如您所述,那么使用wait调用的结果应该跟waitpid一样,但是为什么使用wait却出现信号丢失,而waitpid却没有?
     wait的测试程序如下
     signal(SIGCHLD,sig_chld);
       void sig_chld(int signo){
             pid_t pid;
             int stat;
             pid=wait(&stat);
             return;
      }
        waitpid 的测试程序如下
     void sig_chld(int signo)
       {
               pid_t pid;
               int stat;
               while((pid=waitpid(-1,&stat,WNOHANG))>0);
               return ;
       }
作者: lisp    时间: 2006-04-07 20:53
原帖由 loc1129 于 2006-4-7 20:39 发表
>>"子进程的结束是串行的,如果SIGCHLD信号处理程序的执行时间不是太长的话,父进程应该来得及清理子进程。但如果子进程退出频率过高,可能会导致SIGCHLD信号丢失,这就会产生你提到的不规则的僵死进程 ...

汗,一年前的帖子都被翻出来了。我都是半瓶水,很久没有写程序了,你等高人解答哈。
作者: westgarden    时间: 2006-04-07 21:34
标题: 回复 6楼 loc1129 的帖子
在信号处理程序中会屏蔽当前信号

如果确实是这样的话,
可看看以下我的看法:


wait(&stat);是阻塞型等待
也就是说,wait()要阻塞到所等待的子进程结束才返回。
在这段“等待的子进程结束”的时间内,信号处理程序屏蔽了当前信号SIGCHLD,
父进程也就无法处理其他子进程发的SIGCHLD信号。

waitpid(-1,&stat,WNOHANG)中
WNOHANG会使进程非阻塞地等待。

也就是说,不管等待成功与否,
waitpid(-1,&stat,WNOHANG)都会立即返回,
进程就可以处理其他子进程发的SIGCHLD信号了。
作者: lisp    时间: 2006-04-07 21:49
原帖由 westgarden 于 2006-4-7 21:34 发表

如果确实是这样的话,
可看看以下我的看法:


wait(&stat);是阻塞型等待
也就是说,wait()要阻塞到所等待的子进程结束才返回。
在这段“等待的子进程结束”的时间内,信号处理程序屏蔽 ...

maybe you are right.
作者: loc1129    时间: 2006-04-07 21:57
我测试的背景:一个父进程创建5个子进程,然后这5个子进程差不多在同一时刻递交5个SIGCHLD信号给父进程,测试结果如我前面所说
      那么此时,对于wait来说应该是不阻塞的,它和waitpid一样获得了执行,但为什么结果会不一样呢
作者: lisp    时间: 2006-04-07 22:02
原帖由 loc1129 于 2006-4-7 21:57 发表
我测试的背景:一个父进程创建5个子进程,然后这5个子进程差不多在同一时刻递交5个SIGCHLD信号给父进程,测试结果如我前面所说
      那么此时,对于wait来说应该是不阻塞的,它和waitpid一样获得了执行,但为什 ...

Maybe the  kernel code about signal handling can tell you something,try to read it.
作者: westgarden    时间: 2006-04-07 22:23
原帖由 loc1129 于 2006-4-7 21:57 发表
我测试的背景:一个父进程创建5个子进程,然后这5个子进程差不多在同一时刻递交5个SIGCHLD信号给父进程,测试结果如我前面所说
      那么此时,对于wait来说应该是不阻塞的,它和waitpid一样获得了执行,但为什 ...


不能用人的时间尺度来判断程序到底阻塞不阻塞。

你给让子进程随机sleep一段时间,测试一下看看。
作者: rwen2012    时间: 2006-04-07 22:57
测试过while(waitpid())形式非阻塞形式确实可以解决问题,

哪位高人可以再说说wait为什么不行,
作者: wz_uestc    时间: 2006-04-08 00:41
原帖由 rwen2012 于 2006-4-7 22:57 发表
测试过while(waitpid())形式非阻塞形式确实可以解决问题,

哪位高人可以再说说wait为什么不行,



我来说一下吧!首先记住这样一个事实:“信号可以阻塞但不会排队!”
当父进程正在处理第一个信号的时候,假设第二个信号SIGCHLD到来,它就会被阻塞并添加到待处理信号集里。(运用:信号可以阻塞)
如果这个时候第三个SIGCHLD到来,因为已经有一个待处理信号了,所以第三个SIGCHLD信号会被抛弃。(运用:信号不会排队)
一段时间以后,处理程序返回。内核注意到有一个待处理的SIGCHLD信号,就迫使父进程接受这个信号。父进程捕获这个信号,并第二次调用信号处理程序。处理程序执行完后返回,这个时候已经没有待处理的SIGCHLD信号了(因为第三个已经被抛弃了)!所以第三个子进程成为了僵尸进程!

而如果我们这样使用while((pid=waitpid(-1,NULL,0))>0)
            ……
当第一次执行信号处理函数的时候,就可以回收1、2、3子进程。(最多是第二次就可以全部回收)!

不知道说清楚没有
作者: JohnBull    时间: 2006-04-09 12:19
认真地、仔细地、不要一知半解地读一读APUE.
作者: albcamus    时间: 2006-04-09 13:45
传统Unix信号是不排队的, 较新的Posix实时信号是排队的。
作者: loc1129    时间: 2006-04-09 14:39
原帖由 wz_uestc 于 2006-4-8 00:41 发表

我来说一下吧!首先记住这样一个事实:“信号可以阻塞但不会排队!”
当父进程正在处理第一个信号的时候,假设第二个信号SIGCHLD到来,它就会被阻塞并添加到待处理信号集里。(运用:信号可以阻塞)
如果 ...


测试程序如下
  void sig_chld(int signo)
       {
               pid_t pid;
               int stat;
               while((pid=waitpid(-1,&stat,WNOHANG))>0)
                     sleep(5);
               return ;
       }
然后保证在5秒内向父进程递交3个SIGCHLD,此时按照信号不排队的观点,应该至少有一个SIGCHLD被丢弃,但测试结果是没有一个被丢弃,这好像与不排队的观点相矛盾,为什么?
作者: loc1129    时间: 2006-04-09 14:41
原帖由 albcamus 于 2006-4-9 13:45 发表
传统Unix信号是不排队的, 较新的Posix实时信号是排队的。


unix网络编程 第一卷中介绍,SIGCHLD是UNIX传统信号,应该是要排队的
作者: rwen2012    时间: 2006-04-09 23:01
原帖由 loc1129 于 2006-4-9 14:41 发表


unix网络编程 第一卷中介绍,SIGCHLD是UNIX传统信号,应该是要排队的


??

如果排队直接用wait()不就行了?

还是没有搞清楚
作者: susesuse    时间: 2006-04-10 10:19
顶一下,值得关注这个问题.
作者: 帅绝人寰    时间: 2006-04-10 10:35
原帖由 loc1129 于 2006-4-9 14:41 发表
unix网络编程 第一卷中介绍,SIGCHLD是UNIX传统信号,应该是要排队的


传统信号在deliver时, 先看是否已经有一个这样的sig在排队(注意这个排队指的是不同的信号的bitmap), 如果有, 干脆丢掉当前要deliver的信号。

你的程序说明不了问题的
作者: susesuse    时间: 2006-04-10 12:06
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. #include <sys/types.h>
  5. #include <sys/wait.h>

  6. void sig_child(int signo)
  7. {
  8. pid_t pid;
  9. int stat;
  10. while( (pid = waitpid(-1,&stat,WNOHANG)) > 0)
  11. {
  12. printf("child %d exit\n",pid);
  13. sleep(5);
  14. }
  15. return;
  16. }

  17. void child_func()
  18. {
  19. return;
  20. }

  21. int main()
  22. {
  23. pid_t pid;
  24. int i = 0;

  25. signal(SIGCHLD,sig_child);
  26. for(;i < 5;i ++)
  27. {
  28. if( (pid = fork()) == 0)
  29. {
  30. child_func();
  31. printf("child function finished\n");
  32. exit(0);
  33. }
  34. else if(pid > 0)
  35. {
  36. continue;
  37. }
  38. else
  39. {
  40. printf("fork failed\n");
  41. exit(1);
  42. }
  43. }
  44. return 0;
  45. }
复制代码


上面的代码为啥输出是这样呢(suse 10)?

linux:~/test # gcc -o waitpid waitpid.c
linux:~/test # ./waitpid
child function finished
child 7449 exit
child function finished
child 7450 exit
child function finished
child 7454 exit
child function finished
child 7455 exit
child function finished
child 7459 exit

sigchild信号不是会丢失吗?
作者: loc1129    时间: 2006-04-10 12:16
原帖由 帅绝人寰 于 2006-4-10 10:35 发表


传统信号在deliver时, 先看是否已经有一个这样的sig在排队(注意这个排队指的是不同的信号的bitmap), 如果有, 干脆丢掉当前要deliver的信号。

你的程序说明不了问题的


首先更正我前面的一个贴子:SIGCHLD是不排队的(不好意思,是我打错了)
问题:为什么我的程序说明不了问题
     我的信号处理函数处理一个信号的时间至少是5秒,那么我在5秒内提交至少三个SIGCHLD信号,又因为SIGCHLD不排队,那么照理应该会出现信号丢失的现象,但结果是没有
作者: wz_uestc    时间: 2006-04-10 14:44
原帖由 loc1129 于 2006-4-10 12:16 发表


首先更正我前面的一个贴子:SIGCHLD是不排队的(不好意思,是我打错了)
问题:为什么我的程序说明不了问题
     我的信号处理函数处理一个信号的时间至少是5秒,那么我在5秒内提交至少三个SIGCHLD信号,又 ...



即使信号发生了丢失,但是while( (pid = waitpid(-1,&stat,WNOHANG)) > 0)只要执行,就可以将所有的僵尸进程回收!
再看看我前面的回答,仔细理解一下!
作者: susesuse    时间: 2006-04-10 16:26
也就是说waitpid函数不是由sigchild函数而驱动吧?它是用来检测进程是否已结束的是吗?
作者: cjaizss    时间: 2006-04-10 16:29
当你正在信号处理的时候,传统UNIX只会知道在这段时间里进程接到了什么类型的型号,然而它却无法知道某一种类型的信号具体接收了多少个...
作者: 帅绝人寰    时间: 2006-04-10 17:04
原帖由 cjaizss 于 2006-4-10 16:29 发表
当你正在信号处理的时候,传统UNIX只会知道在这段时间里进程接到了什么类型的型号,然而它却无法知道某一种类型的信号具体接收了多少个...

这是正解。 其他的不必多说了, 看APUE去吧!
作者: gooderfeng    时间: 2006-04-10 17:09
当你正在信号处理的时候,传统UNIX只会知道在这段时间里进程接到了什么类型的型号,然而它却无法知道某一种类型的信号具体接收了多少个...

传统的,那现在的linux 可以把信号做成排队的吗???
作者: loc1129    时间: 2006-04-10 22:46
原帖由 wz_uestc 于 2006-4-10 14:44 发表



即使信号发生了丢失,但是while( (pid = waitpid(-1,&stat,WNOHANG)) > 0)只要执行,就可以将所有的僵尸进程回收!


能解释一下为什么“即使信号丢失,但只要运行while( (pid = waitpid(-1,&stat,WNOHANG)) > 0)就可以将所有的僵尸进程回收
作者: rwen2012    时间: 2006-04-11 11:58
原帖由 susesuse 于 2006-4-10 16:26 发表
也就是说waitpid函数不是由sigchild函数而驱动吧?它是用来检测进程是否已结束的是吗?


可不可以这样理解?
作者: wz_uestc    时间: 2006-04-11 12:22
原帖由 rwen2012 于 2006-4-11 11:58 发表


可不可以这样理解?



应该可以这样说吧!
重点是使用了while循环!
如果不用while循环,也达不到上述效果!
作者: lanying_wzw    时间: 2008-05-20 15:27
楼主混淆了两个问题:
一是信号是否排队
二是多个子进程结束时是否会丢失对某个子进程的退出处理

第一个问题是大多数UNIX系统不对信号排队
第二个问题是可以在某个子进程的处理函数里while(watipid())来处理其它子进程的退出,所以就不用担心某个子进程退出主进程不知道的的问题。

楼主的本意也许是“主进程能否处理所有子进程的退出”
作者: maxxfire    时间: 2009-03-31 11:07
原帖由 susesuse 于 2006-4-10 12:06 发表
#include
#include
#include
#include
#include

void sig_child(int signo)
{
pid_t pid;
int stat;
while( (pid = waitpid(-1,&stat,WNOHANG)) > 0)
{
printf("child %d exit\n",pid);
sle ...



你这个程序有问题,你的程序的执行过程是:
father fork child 1
child 1 exit
father handle sigchild 1
这个时候:
father fork child 2
child 2 exit
father handle sigchild 1
以此类推
...

因为father刚fork完child1就接到sigchild1,所以先去执行sigchild1而导致无法继续fork child2。所以整个过程实际上变成只有2个进程再跑了,你要等child全部fork完,然后再全部同时死去,这样就会出现信号丢失了,真正只处理了第一信号,看我改后的程序:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

int total=0;

void sig_child(int signo)
{
pid_t pid;
int stat;
//while( (pid = waitpid(-1,&stat,WNOHANG)) > 0)
if(1)
{
printf("child %d exit\n",total++);
sleep(1);
}
return;
}

void child_func()
{
sleep(5); //let child wait...
return;
}

int main()
{
pid_t pid;
int i = 0;

signal(SIGCHLD,sig_child);
for(;i < 100;i ++)
{
if( (pid = fork()) == 0)
{
pid_t child=getpid();
printf("child[%d] function start..\n",child);
child_func();
printf("child[%d] function finished!\n",child);
fflush(stdout);
exit(0);
}
else if(pid > 0)
{
continue;
}
else
{
printf("fork failed\n");
exit(1);
}
}

printf("Father waiting for sigchild...\n");
pause();
return 0;
}

作者: scut_tang    时间: 2009-12-17 16:28
不好意思,把僵尸贴拉了出来,我想问下:

1    void sig_chld(int signo)
2    {
3          pid_t pid;
4          int stat;
5          while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0 )
6               printf("child %d terminated\n", pid);
7           return;
8     }

如果在第5个语句(waitpid返回0)与第7个语句(或者说退出sig_chld函数前)之间又有SIGCHLD信号发过来,那不是又有可能产生僵尸进程?
我的理解是不同类型的信号是排队的,相同类型的信号是不排队的,也就是信号处理程序屏蔽了当前信号SIGCHLD,
父进程也就无法处理其他子进程发的SIGCHLD信号。

[ 本帖最后由 scut_tang 于 2009-12-17 16:38 编辑 ]
作者: c/unix    时间: 2009-12-17 16:42
提示: 作者被禁止或删除 内容自动屏蔽
作者: scut_tang    时间: 2009-12-17 19:04
原帖由 c/unix 于 2009-12-17 16:42 发表


对,是会产生僵死进程。不是用while回收了吗

我的意思是当waitpid返回0,然后SIGCHLD信号发送过来,但是父进程还处于sig_chld信号处理函数里面,那不是把SIGCHLD信号丢掉了?
作者: c/unix    时间: 2009-12-17 21:12
提示: 作者被禁止或删除 内容自动屏蔽
作者: iceyang1989    时间: 2012-02-21 20:03
a 回复下是为了保存帖子回家学习
作者: _print    时间: 2012-02-24 22:36
c/unix 发表于 2009-12-17 21:12
就是把他丢了,如果不丢就不用用while了


:wink:
作者: iziang    时间: 2013-07-14 16:48
可以理解为,(wait,waitpid)与SIGCHLD无关,调用wait和waitpid不依赖SIGCHLD,即使丢失了SIGCHLD,两个函数也可以得到终止子进程的信息




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2