10.7 SIGCHLD定义

Posted U201013687

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10.7 SIGCHLD定义相关的知识,希望对你有一定的参考价值。

经常混淆的两个信号就是SIGCLD以及SIGCHLD,信号SIGCLD源于System V,该信号的含义与源自BSD的信号SIGCHLD不一致。同时POSIX.1信号也称为SIGCHLD.源自BSD的信号SIGCHLD的语义比较正常,当该信号出现的时候,表示子进程的状态发生了变化,然后我们需要调用一个wait函数来查看究竟发生了什么。

System V对于SIGCLD的处理历史以来都与其他信号不同,基于SVR4i的系统保持了这个有问题的传统,如果我们使用函数signal或者是sigset(SVR3中用于设置信号处理函数的函数)设置信号的处理函数,SIGCLD早期的处理包含如下行为:

  1. 如果将信号处理函数指定为SIG_IGN,调用进程的子进程将永远不会产生僵尸进程。注意这与该信号的默认处理时不同的,在图10.1中提到其默认处理时忽略。取而代之的是,当子进程终止的时候,子进程的状态将被抛弃,如果其父进程接着调用其中一个wait函数,调用进程将被阻塞直到所有子进程终止,然后wait函数返回-1,并且errno被设置为ECHILD.(注意:信号的默认处理时忽略信号,但是该默认处理方式并不会产生上述行为,而是我们必须将该信号的处理函数设置为SIG_IGN.)

    POSIX.1并没有指定当SIGCHLD被忽略的时候会发生什么,所以上述处理也是被允许的,而XSI选项要求这一处理被信号SIGCHLD支持。
    4.4BSD在SIGCHLD被忽略的时候总是生成僵尸进程,如果我们想要避免僵尸进程的产生,我们必须wait所有的子进程,在SVR4中,只要调用signal或者是sigset中的一个将SIGCHLD的处理函数设置为SIG_IGN,僵尸进程就永远不会产生,本书中描述的4个平台都与SVR4的相同。
    使用函数sigaction而言,我们可以设置SA_NOCLDWAIT标志来避免僵尸进程,该行为对于本书中介绍的4个平台都是支持的。

  2. 如果我们设置SIGCLD的处理函数,内核就会立即检查是否有子进程处于等待处理的情况,若有,则立即调用SIGCLD函数。

上述第二项改变了我们编写信号处理函数的方式,正如下面的例子中将会讲到的一样.

Example

在10.4节中提到,在信号处理函数中的第一件事就是再次调用signal函数,这样处理时为了最小化信号处理函数被还原为默认处理的时间窗口,图10.6就是按照这一规则进行编写的程序,但是该程序在传统的System V平台上并不能很好地工作,其输出将是连续不断的字符串”SIGCLD received”,最会进程由于堆栈空间溢出而异常终止。

  1. #include "apue.h"
  2. #include <sys/wait.h>
  3. static void sig_cld(int signo);
  4. int main()
  5. {
  6. pid_t pid;
  7. if(signal(SIGCLD, sig_cld) == SIG_ERR)
  8. perror("signal error");
  9. if((pid = fork()) < 0)
  10. {
  11. perror("fork error");
  12. }
  13. else if(pid == 0)
  14. {
  15. /* child process*/
  16. sleep(2);
  17. _exit(0);
  18. }
  19. pause(); /*parent process*/
  20. exit(0);
  21. }
  22. static void sig_cld(int signo)
  23. {
  24. pid_t pid;
  25. int status;
  26. printf("SIGCLD received\n");
  27. if(signal(SIGCLD, sig_cld) == SIG_ERR) /*reestablish handler*/
  28. perror("signal error");
  29. if((pid = wait(&status)) < 0) /*fetch child status*/
  30. perror("wait error");
  31. printf("pid = %d\n", pid);
  32. }

上述程序的问题是:在信号处理函数的开始位置调用了函数signal,这对应于上面讨论的第二项–内核检查是否有子进程需要wait for(在上述程序中符合这一情况,因为我们正在处理SIGCLD信号),所以对于signal函数的调用会产生另一次对于信号处理函数的调用,信号处理函数反过来又会调用signal函数,于是整个进程就会不断地重复运行。
为了解决上述程序的问题,我们必须将对函数signal的调用移动到wait函数之后,通过这样做我们在捕获到子进程的终止状态以后再调用signal函数,该信号仅仅在其他子进程终止的时候才会再次产生。

POSIX.1声明:在我们建立SIGCHLD的信号处理函数的时候,如果已经存在一个还没有被wait的终止的子进程,信号是否需要生成并没有指定,因此上述情况是允许的,但是对于POSIX.1而言,在信号产生以后并不会复位信号处理函数为默认函数(假设我们正在使用的是POSIX.1的sigaction函数来设置信号处理函数),便没有需要在信号处理函数中再次调用函数signal了。于是上述问题就消失了。





以上是关于10.7 SIGCHLD定义的主要内容,如果未能解决你的问题,请参考以下文章

子进程是否也应该解除阻塞的SIGCHLD信号?

在 10.6 上测试 Mac OS X 10.7 特定代码时出现“未找到符号”崩溃

VSCode自定义代码片段——CSS选择器

Chp10 10.7

VSCode自定义代码片段6——CSS选择器

VSCode自定义代码片段——声明函数