linux wait函数 : 处理僵尸进程(进程回收)

进程回收

  在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要指进程控制块 PCB 的信息(进程号、退出状态、运行时间等)

  父进程可以通过调用 wait  或  waitpid  得到它的退出状态同时彻底清除这个进程。

  wait()  和  waitpid()  函数的功能一样,区别在于,wait() 函数会阻塞, waitpid() 可以设置不阻塞, waitpid()  还可以指定等待那个子进程结束

  注意:一次 wait  或  waitpid  调用只能清理一个子进程,清理多个子进程应使用循环

--wait函数

复制代码
 1 /*
 2     man 2 wait
 3     #include <sys/types.h>
 4     #include <sys/wait.h>
 5     pid_t wait(int* wstatus);
 6         功能:等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收子进程资源
 7         参数:
 8             int* wstatus
 9             进程退出时的状态信息,传入的是一个 int 类型的地址, 传出参数
10         返回值:
11             - 成功: 返回被回收的子进程的 id
12             - 失败: -1(所有的子进程都结束,函数调用失败)
13     调用wait函数的进程会被挂起(阻塞),直到它的一个子进程退出或者收到一个不能被忽略的信号时,才被唤醒(继续执行)
14     如果没有子进程了,函数立刻返回,返回 -1, 如果子进程都已经结束了,也会立即返回, 返回 -1
15 */
16 #include <sys/types.h>
17 #include <sys/wait.h>
18 #include <stdio.h>
19 #include <unistd.h> //fork
20 #include <stdlib.h>
21 int main()
22 {
23     //有一个父进程,创建5个子进程(兄弟)
24     pid_t pid;
25 
26     for(int i = 0; i < 5; i++)
27     {
28         pid = fork();//如果不给子进程break 会产生 孙子进程 即 子进程的子进程 
29         if(pid == 0)
30         {
31             break;
32         }
33     }
34     if(pid > 0)
35     {
36         //父进程
37         while(1)
38         {
39             printf("Parent process,pid = %d\n",getpid());
40             int ret = wait(NULL);//不需要获取子进程状态
41             printf("Child die,pid = %d\n",ret);//失败 返回 -1
42             sleep(1);
43         }
44     }
45     else if(pid == 0)
46     {
47         //子进程
48         while(1)
49         {
50             printf("Child, pid = %d\n",getpid());
51             sleep(1);
52         }
53         //kill -9 进程号 终端杀死进程
54         //若不执行 40行执行后  父进程会阻塞  执行kill杀死子进程后  父进程继续执行  即执行41行,但仅释放了一个行为
55     }
56     //ps aux 查询当前执行的 进程 
57     return 0;
58 }
复制代码

退出信息示例

复制代码
 1  if(pid > 0)
 2     {
 3         //父进程
 4         while(1)
 5         {
 6             printf("Parent process,pid = %d\n",getpid());
 7             int st;
 8             int ret = wait(&st);
 9             if(ret == -1)//失败 返回-1  break;
10             {
11                 break;
12             }
13             if(WIFEXITED(st))
14             {
15                 //是不是正常退出
16                 printf("退出的状态码:%d\n",WEXITSTATUS(st));//输出:0   --  exit(0)  
17             }
18             if(WIFSIGNALED(st))
19             {
20                 //是不是异常终止
21                 printf("被那个信号干掉了:%d\n",WTERMSIG(st));//终端键入 kill -9 进程号
22                 //输出  被那个信号干掉了: 9
23             }
24             printf("Child die,ret = %d, pid = %d\n",ret,getpid());
25             sleep(1);
26         }
27     }
复制代码

退出信息相关宏函数

复制代码
1 WIFEXITED(status)     //非0  进程正常退出
2 WEXITSTATUS(status)   //如果上宏为真  获取进程退出的状态(exit的参数)
3 
4 WIFSIGNALED(status)   //非0 进程异常终止
5 WTERMSIG(status)     //如果上宏为真,获取使进程终止的信号编号
6 
7 WIFSTOPPED(status)    //非0 进程处于暂停状态
8 WSTOPSIG(status)     //如果上宏为真,获取使进程暂停的信号的编号
9 WIFCONTINUED(status)  //非0,进程暂停后已经继续运行
复制代码

--waitpid函数   

复制代码
 1 /*
 2     man 2 waitpid
 3     ps  ajx : 查询 进程的 pid ppid  进程组
 4     进程组 A有BCD三个子进程  ABC一个组 D可以分给其他组 因此 释放A组的子进程 D没有被释放
 5     #include <sys/types.h>
 6     #include <sys/wait.h>
 7     pid_t waitpid(pid_t pid, int* wstatus, int options);
 8         功能:回收指定进程号的子进程,可以设置是否阻塞
 9         参数:  
10             - pid:
11                 pid > 0: 某个子进程的pid
12                 pid = 0: 回收当前 进程组 的所有子进程
13                 pid = -1: 回收所有的子进程,相当于 wait()        ***最常用***
14                 pid < -1: 某个 进程组 的 组id的 绝对值,回收指定进程组中的子进程
15             - options:设置阻塞或者非阻塞
16                 0:阻塞
17                 WNOHANG():非阻塞
18         返回值:
19             > 0: 返回子进程的id
20             = 0: options = WNOHANG,表示还有子进程活着
21             = -1: 错误,或者没有子进程
22 */
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <stdio.h>
26 #include <unistd.h> //fork
27 #include <stdlib.h>
28 int main()
29 {
30     //有一个父进程,创建5个子进程(兄弟)
31     pid_t pid;
32 
33     for(int i = 0; i < 5; i++)
34     {
35         pid = fork();//如果不给子进程break 会产生 孙子进程 即 子进程的子进程 
36         if(pid == 0)
37         {
38             break;
39         }
40     }
41     if(pid > 0)
42     {
43         //父进程
44         while(1)
45         {
46             printf("Parent process,pid = %d\n",getpid());
47             int st;
48             int ret = waitpid(-1,&st,0);//默认为阻塞状态
49             if(ret == -1)
50             {
51                 break;
52             }
53             if(WIFEXITED(st))
54             {
55                 //是不是正常退出
56                 printf("退出的状态码:%d\n",WEXITSTATUS(st));//输出:0   --  exit(0) 
57             }
58             if(WIFSIGNALED(st))
59             {
60                 //是不是异常终止
61                 printf("被那个信号干掉了:%d\n",WTERMSIG(st));//终端键入 kill -9 进程号
62                 //输出  被那个信号干掉了: 9
63             }
64             printf("Child die,ret = %d, pid = %d\n",ret,getpid());
65             sleep(1);
66         }
67     }
68     else if(pid == 0)
69     {
70         //子进程
71         while(1)
72         {
73             printf("Child, pid = %d\n",getpid());
74             sleep(1);
75         }
76         exit(0);
77     }
78     return 0;//exit(0);
79 }
复制代码

此时终端显示:

         

posted on   廿陆  阅读(203)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示