进程控制2(进程等待,status参数分析,阻塞非阻塞等待状态分析)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liu_zhen_kai/article/details/81840262

进程等待

进程等待的必要性

  • 当子进程退出而父进程继续工作不回收子进程资源,那么就会产生僵尸进程。
  • 僵尸进程危害很大,kill -9 也无法杀死僵尸进程
  • 当子进程完成工作后父进程需要直到子进程是否完成,是否异常
  • 父进程需要等待子进程的退出信息来回收子进程的所有资源,避免资源泄露

进程等待方法

  • 调用系统调用接口wait
pid_t wait(int *status);

参数status是一个输出型参数,用来保存退出信息与终止信号//后文详细讲到,不关心退出状态可以设置为NULL

返回值wait():  on  success, returns the process ID of the terminated child; on error, -1 is
       returned.

如果等待成功,返回等待的子进程的pid,等待失败则返回-1

功能:等待任意一个子进程直到退出或者被替换

例子

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>
  4 #include <sys/wait.h>
  5 #include <unistd.h>
  6 
  7 int main(void)
  8 {
  9     pid_t pid = fork();
 10 
 11     if(pid < 0){
 12         perror("fork"),
 13             exit(0);
 14     }
 15     else if(pid == 0)
 16     {
 17         int i = 5;
 18         while(i--)
 19         {
 20             printf("sleep %d\n", i);
 21             sleep(1);
 22         }
 23         printf("child pid is : %d\n", getpid());
 24         exit(0);
 25     }
 26     else
 27     {
 28         int ret = wait(NULL);
 29         printf("wait finish , return : %d\n", ret);
 30     }
 31 
 32     return 0;
 33 }
//运行结果
[liu@localhost wait_waitpid]$ !cc
cc wait.c -o wait
[liu@localhost wait_waitpid]$ ./wait 
sleep 4
sleep 3
sleep 2
sleep 1
sleep 0
child pid is : 20309
wait finish , return : 20309
[liu@localhost wait_waitpid]$ 

sleep五秒之后返回子进程pid

  • 调用系统调用接口waitpid
pid_t waitpid(pid_t pid, int *status, int options);
参数:
pid:The value of pid can be:

       < -1   meaning  wait  for  any  child  process whose process group ID is equal to the
              absolute value of pid.

       -1     meaning wait for any child process.//等待任意一个子进程

       0      meaning wait for any child process whose process group ID is equal to that  of
              the calling process.

       > 0    meaning wait for the child whose process ID is equal to the value of pid.//pid等待指定子进程

status:同wait
options:选择等待方式,0为默认阻塞等待方式,WNOHANG为非阻塞等待方式


返回值:
       on success, returns the process ID of the child whose state  has  changed;
 by pid exist, but have not yet changed state, then 0 is returned.  On error, -1 is returned.

等待成功返回被等待的子进程pid,失败返回-1,但是当options选用的WNOHANG而子进程还在运行或未被替换时,返回0.

例子

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>
  4 #include <sys/wait.h>
  5 #include <unistd.h>
  6 
  7 int main(void)
  8 {
  9     pid_t pid = fork();
 10 
 11     if(pid < 0){
 12         perror("fork"),
 13             exit(0);
 14     }
 15     else if(pid == 0)
 16     {
 17         int i = 5;
 18         while(i--)
 19         {
 20             printf("sleep %d\n", i);
 21             sleep(1);
 22         }
 23         printf("child pid is : %d\n", getpid());
 24         exit(0);
 25     }
 26     else
 27     {
 28         int ret = waitpid(-1, NULL,0);
 29         printf("waitpid finish , return : %d\n", ret);
 30     }
 31 
 32     return 0;
 33 }
//运行结果
[liu@localhost wait_waitpid]$ ./waitpid 
sleep 4
sleep 3
sleep 2
sleep 1
sleep 0
child pid is : 20391
waitpid finish , return : 20391

status参数分析

  • 无论是在wait还是waitpid中都有一个参数status
  • status作为获得型参数由操作系统填充,可以保存子进程的退出信息以及被终止信号
  • 当status为NULL时表示不关心子进程的退出信息

上文提到status能获取子进程的退出状态和终止信号,但是status是整形(因为系统需要改变status的值所以才传整形指针int* )如何来存储这么多信息呢?

例子:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>
  4 #include <sys/wait.h>
  5 #include <unistd.h>
  6 
  7 int main(void)
  8 {
  9     pid_t pid = fork();
 10 
 11     if(pid < 0){
 12         perror("fork"),
 13             exit(0);
 14     }
 15     else if(pid == 0)
 16     {
 17         int i = 5;
 18         while(i--)
 19         {
 20             printf("sleep %d\n", i);
 21             sleep(1);
 22         }
 23         printf("child pid is : %d\n", getpid());
 24         exit(123);
 25     }
 26     else
 27     {
 28         int status;
 29         int ret = waitpid(-1, &status,0);
 30         printf("waitpid finish , return : %d\n", ret);
 31         printf("status is %d\n", status);
 32     }
 33 
 34     return 0;
 35 }

按照道理来说子进程退出码为123,那么保存退出信息的参数status也就为123

运行结果:
[liu@localhost wait_waitpid]$ ./waitpid 
sleep 4
sleep 3
sleep 2
sleep 1
sleep 0
child pid is : 20433
waitpid finish , return : 20433
status is 31488

但是status的值为31488

status如何实现保存信息?
答案是用bitmap,位图结构保存信息,一个整型32个比特位,上十六位先不做研究,下十六个比特位又分成低八位和次低八位。次低八位(255)保存退出码,低八位(255)保存终止信号,这样就实现了仅用一个int空间就保存了多种信息
这里写图片描述

下面通过代码来证实这个说法

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>
  4 #include <sys/wait.h>
  5 #include <unistd.h>
  6 
  7 int main(void)
  8 {
  9     pid_t pid = fork();
 10 
 11     if(pid < 0){
 12         perror("fork"),
 13             exit(0);
 14     }
 15     else if(pid == 0)
 16     {
 17         int i = 5;
 18         while(i--)
 19         {
 20             printf("sleep %d\n", i);
 21             sleep(1);
 22         }
 23         printf("child pid is : %d\n", getpid());
 24         exit(123);
 25     }
 26     else
 27     {
 28         int status;
 29         int ret = waitpid(-1, &status,0);
 30         printf("waitpid finish , return : %d\n", ret);
 31         printf("kill sig : %d\n", status&127);//取低八位后七位(第八位core dump标志)
 32         printf("exit sig : %d\n", (status>>8)&255);//取次低八位
 33     }
 34     
 35     return 0;
 36 }
运行结果 
[liu@localhost wait_waitpid]$ ./waitpid 
sleep 4
sleep 3
sleep 2
sleep 1
sleep 0
child pid is : 20518
waitpid finish , return : 20518
kill sig : 0
exit sig : 123

启动其他终端发kill -9 命令杀死进程后

[liu@localhost wait_waitpid]$ ./waitpid 
pid : 20553
sleep 4
waitpid finish , return : 20553
kill sig : 9
exit sig : 0
[liu@localhost wait_waitpid]$ 

打印终止信号,所以证实了之前的所有说法。

另外,Linux操作系统提供了对于status返回值提取信号的宏定义

WTERMSIG(status)
              returns the number of the signal that caused the child process to terminate.  This macro should only be employed if WIFSIGNALED returned true. 
              返回子进程的终止信号

WEXITSTATUS(status)
              returns  the  exit  status of the child.  This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as
              the argument for a return statement in main().  This macro should only be employed if WIFEXITED returned true.
返回子进程的退出状态 

阻塞非阻塞状态分析

在waitpid接口中,提供阻塞状态与非阻塞状态两种等待方式

  • 阻塞等待:在等待子进程退出或替换之前,停止一切活动
  • 非阻塞等待:在子进程退出或替换之前,还可以继续完成自己的工作
The value of options is an OR of zero or more of the following constants:

       WNOHANG     return immediately if no child has exited.

当选定WNOHANG状态时,发生非阻塞等待

waitpid(): on success, returns the process ID of the child whose state  has  changed;
       if  WNOHANG was specified and one or more child(ren) specified by pid exist, but have
       not yet changed state, then 0 is returned.  On error, -1 is returned.
返回值为0并表示还在等待,返回值大于0表示等待成功的子进程pid,-1为等待失败。

例子

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>
  4 #include <sys/wait.h>
  5 #include <unistd.h>
  6 
  7 int main(void)
  8 {
  9     pid_t pid = fork();
 10 
 11     if(pid < 0){
 12         perror("fork"),
 13             exit(0);
 14     }
 15     else if(pid == 0)
 16     {
 17         int i = 5;
 18         while(i--)
 19         {
 20             printf("sleep %d\n", i);
 21             sleep(2);
 22         }
 23         exit(0);
 24     }
 25     else
 26     {
 27         while(1)
 28         {
 29             int ret = waitpid(-1, NULL,WNOHANG);
 30                 if(ret == -1)
 31                     perror("waitpid"),
 32                         exit(0);
 33                 else if(ret == 0)
 34                 {
 35                     printf("child process is not finished\n");
 36                 }
 37                 else
 38                 {
 39                     printf("child finised\n");
 40                     break;
 41                 }
 42                     
 43                 sleep(1);
 44         }       
 45     }           
 46     return 0;       
 47 }       

在子进程未完成之前,父进程每隔一秒进行轮询访问,进行非阻塞状态等待。

运行结果 
[liu@localhost wait_waitpid]$ ./waitpid 
child process is not finished
sleep 4
child process is not finished
child process is not finished
sleep 3
child process is not finished
sleep 2
child process is not finished
child process is not finished
sleep 1
child process is not finished
child process is not finished
sleep 0
child process is not finished
child process is not finished
child finised

猜你喜欢

转载自blog.csdn.net/liu_zhen_kai/article/details/81840262