0
点赞
收藏
分享

微信扫一扫

0基础学会SIGCHLD()信号的使用(可以解决僵尸进程的问题,内附C语言代码)

楠蛮鬼影 2022-03-13 阅读 75

SIGCHLD信号产生的3个条件:

1、子进程结束;

2、子进程暂停了;

3、子进程继续运行;

都会给父进程发送该信号,父进程默认忽略此信号。

接下来使用代码来解释这个问题:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/time.h>
  4 #include <unistd.h>
  5 #include <signal.h>
  6 #include <sys/wait.h>
  7 #include <signal.h>
  8 void myfun(int num)
  9 {
 10         printf("catch you,id:%d\n",num);//获取捕捉的信号
 11         while(1)
 12         {
 13                 int ret=waitpid(-1,NULL,WNOHANG);//等待回收子进程
 14                 if(ret>0)
 15                 {//回收的子进程
 16                         printf("child die,id:%d\n",ret);//已经回收的子进程
 17                 }
 18                 else if(ret==0)//子进程已经获取完毕
 19                 {
 20                         break;
 21                 }
 22                 else if(ret==-1)//出现错误
 23                 {
 24                         break;
 25                 }
 26         sleep(1);
 27 
 28         }
 29 
 30 }
 31 int main()
 32 {
 33         pid_t pid;
 34         for(int i=0;i<10;i++)
 35         {
 36                 pid=fork();//创建10个子进程
 37                 if(pid==0)
 38                 {
 39                         //子进程
 40                         break;
 41                 }
 42         }
 43         if(pid>0)//父进程
 44         {
 45                 struct sigaction act;
 46                 act.sa_flags=0;
 47                 act.sa_handler=myfun;
 48                 sigemptyset(&act.sa_mask);
 49                 int ret=sigaction(SIGCHLD,&act,NULL);//使用SIGCHLD解决僵尸问题
 50                 if(ret==-1)
 51                 {
 52                         perror("sigaction");
 53                         exit(2);
 54                 }
 55                 while(1)
 56                 {
 57                         printf("perent process id:%d\n",getpid());
 58                         sleep(1);
 59                 }
 60         }
 61         else if(pid==0)
 62         {
 63                 printf("child process id:%d\n",getpid());
 64         }
 65 
 66         return 0;
 67        }

其运行结果如下: 

 

 分析:在上述程序中,每个子进程在结束之前都会睡眠1s,这是为了留出足够的时间保证在所有子进程结束之前,父进程能够完成对SIGCHLD信号的注册(红色标1的地方)。否则所有子进程都结束了,父进程还没有完成注册,则此时信号都被忽略,从而子进程不能被父进程回收。但是,只要有一个子进程在信号注册后结束,所有子进程都可以被回收(红色标2的地方),因为使用了while循环回收子进程。红色标3的地方就是完成了父进程对子进程的回收。除了使用sleep函数来实现这一点外,其实更加高效而又精确的办法(其实在负载较大的 情况下,sleep函数也不能确保能够做到)就是在父进程注册函数之前就将SIGCHLD信号设置为阻塞(通过信号集操作函数加入到屏蔽字中),在注册完成时立即解除对该信号的阻塞即可。

接下来,我们一起来看通过信号集操作函数加入屏蔽字的相关代码:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/time.h>
  4 #include <unistd.h>
  5 #include <signal.h>
  6 #include <sys/wait.h>
  7 #include <signal.h>
  8 void myfun(int num)
  9 {
 10         printf("catch you,id:%d\n",num);//获取捕捉的信号
 11         while(1)
 12         {
 13                 int ret=waitpid(-1,NULL,WNOHANG);//等待回收子进程
 14                 if(ret>0)
 15                 {//回收的子进程
 16                         printf("child die,id:%d\n",ret);//已经回收的子进程
 17                 }
 18                 else if(ret==0)//子进程已经获取完毕
 19                 {
 20                         break;
 21                 }
 22                 else if(ret==-1)//出现错误
 23                 {
 24                         break;
 25                 }
 26         sleep(1);
 27 
 28         }
 29 
 30 }
 31 int main()
 32 {
            sigset_t set;
 34         sigemptyset(&set);
 35         sigaddset(&set,SIGCHLD);
 36         sigprocmask(SIG_BLOCK,&set,NULL);
 37         //注册完信号捕捉之后,解除阻塞
 38         sigprocmask(SIG_UNBLOCK,&set,NULL);

 33         pid_t pid;
 34         for(int i=0;i<10;i++)
 35         {
 36                 pid=fork();//创建10个子进程
 37                 if(pid==0)
 38                 {
 39                         //子进程
 40                         break;
 41                 }
 42         }
 43         if(pid>0)//父进程
 44         {
 45                 struct sigaction act;
 46                 act.sa_flags=0;
 47                 act.sa_handler=myfun;
 48                 sigemptyset(&act.sa_mask);
 49                 int ret=sigaction(SIGCHLD,&act,NULL);//使用SIGCHLD解决僵尸问题
 50                 if(ret==-1)
 51                 {
 52                         perror("sigaction");
 53                         exit(2);
 54                 }
 55                 while(1)
 56                 {
 57                         printf("perent process id:%d\n",getpid());
 58                         sleep(1);
 59                 }
 60         }
 61         else if(pid==0)
 62         {
 63                 printf("child process id:%d\n",getpid());
 64         }
 65 
 66         return 0;
 67        }

 经过测试,与上面的运行结果一致。


 

举报

相关推荐

0 条评论