进程的资源回收
- 进程终止以后,如果父进程不来回收子进程的资源,相当于子进程的用户态已经结束了,但是内核态没有,子进程的PCB还在占用着资源。这个PCB有时被称为进程的僵尸(白白占用系统的内存)。所以在子进程结束以后要及时的回收子进程的僵尸。
1. wait
1.1 可以使用以下 宏检测进程终止的原因
$ man 2 wait
....
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
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 be employed only if WIFEX‐
ITED returned true.
WIFSIGNALED(status)
returns true if the child process was terminated by a signal.
WTERMSIG(status)
returns the number of the signal that caused the child process to terminate. This macro should be employed only if WIFSIGNALED
returned true.
....
1.2 代码示例
wait.c
#include <stdlib.h>
#include "t_stdio.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
int s;
//创建子进程
pid_t pid = fork();
if(pid==-1)E_MSG("fork", -1);
if(pid == 0){
//子进程执行代码
printf("child process ... %d\n", getpid());
getchar();
// 终止子进程
exit(-1);
} else {
// 父进程执行代码
// wait 阻塞等待子进程结束, 回收子进程资源, 所以子进程执行完以后才会执行下面的printf的代码, 这样就从之前的异步,变成了现在的同步
// s用来存储子进程的退出状态码
wait(&s);
if(WIFEXITED(s)){ // WIFEXITED(s) 为真说明子进程正常退出,WEXITSTATUS(s)可以获取子进程退出状态码
printf("exit: %d\n", WEXITSTATUS(s));
}
if(WIFSIGNALED(s)){ // WIFSIGNALED(s) 为真说明进程是被信号打断的, WTERMSIG(s) 可以获取打断进程信号的编号
printf("signum: %d\n", WTERMSIG(s));
}
printf("father process ...\n");
}
return 0;
}
- 子进程正常退出
- 子进程被信号打断
↓
2. waitpid
- wait 是等待任意子进程,只要是子进程终止那么就把它给回收
- waitpid 可以指定某一个子进程的pid,也可以指定某一个进程组的pid
2.1 pid 参数取值说明
- pid == -1, option==0 时waitpid 完全等同于 wait
- 进程组包含多个进程,每个进程组里都有leader进程,leader进程的pid就是这个进程组的pid
- 一般情况下父进程调用fork创建子进程以后,不调用setpgid,那么子进程和父进程都是同组的,如果调用了setpgid, 那么子进程将会被设置为另一个进程组的进程。
waitpid.c
#include <stdlib.h>
#include "t_stdio.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
int s;
//创建子进程
pid_t pid = fork();
if(pid==-1)E_MSG("fork", -1);
if(pid == 0){
//子进程执行代码
printf("child process ... %d\n", getpid());
getchar();
// 终止子进程
exit(-1);
} else {
// 父进程执行代码
// waitpid(-1, &s, 0); 这是阻塞模式收子进程的资源. 阻塞: 如果要回收的子进程还没有结束, 等着结束回收资源以后再去执行下面的
// waitpid(-1, &s, WNOHANG); 这是非阻塞模式收子进程的资源。非阻塞: 如果要回收的子进程还没有结束,waitpid直接返回0, 不等子进程了
int w=waitpid(-1, &s, WNOHANG);
if(w==0){// 没有子进程的资源要回收(因为子进程还没有结束),直接结束
printf("parent exit ...\n");
return 0;
}
// 返回值不是0,说明有子进程资源的要回收(子进程已经结束了), 再根据返回的状态码来判断子进程是怎么终止的
if(WIFEXITED(s)){ // WIFEXITED(s) 为真说明子进程正常退出,WEXITSTATUS(s)可以获取子进程退出状态码
printf("exit: %d\n", WEXITSTATUS(s));
}
if(WIFSIGNALED(s)){ // WIFSIGNALED(s) 为真说明进程是被信号打断的, WTERMSIG(s) 可以获取打断进程信号的编号
printf("signum: %d\n", WTERMSIG(s));
}
printf("father process ...\n");
}
return 0;
}
# 父进程没有等子进程直接终止
$ ./a.out
parent exit ...
child process ... 30610
孤儿进程和僵尸进程
- 上图的init 改为 upstart
1. 孤儿进程代码示例
#include "t_stdio.h"
#include <unistd.h>
#include <sys/types.h>
int main(void){
pid_t pid = fork();
if(pid == -1)E_MSG("fork", -1);
if(pid == 0){
// 在子进程中执行的代码
printf("父进程还没终止时的pid: %d", getppid());
printf("子进程的pid: %d\n", getpid());
sleep(2);
printf("父进程终止以后,但是子进程没有终止情况下,父进程的pid: %d", getppid());
} else {
// 在父进程中执行的代码
sleep(1);
printf("parent process ...\n");
}
return 0;
}
$ ./a.out
父进程还没终止时的pid: 27663子进程的pid: 27664
parent process ...
$ 父进程终止以后,但是子进程没有终止情况下,父进程的pid: 2524
$ ps -aux| grep 2524
moonx 2524 0.0 0.0 48216 2512 ? Ss 11月23 0:19 /sbin/upstart --user
moonx 28021 0.0 0.0 15968 1080 pts/21 S+ 19:23 0:00 grep --color=auto 2524
2. 僵尸进程代码示例
#include <stdlib.h>
#include "t_stdio.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
int s;
//创建子进程
pid_t pid = fork();
if(pid==-1)E_MSG("fork", -1);
if(pid == 0){
//子进程执行代码
exit(-1);
} else {
// 父进程执行代码
getchar();
wait(NULL);
}
return 0;
}
$ ./a.out
## 再打开一个shell,子进程 [a.out] <defunct> 处于僵尸状态 Z+
$ ps -aux| grep a.out
moonx 32381 0.0 0.0 4356 600 pts/21 S+ 19:30 0:00 ./a.out
moonx 32382 0.0 0.0 0 0 pts/21 Z+ 19:30 0:00 [a.out] <defunct>
moonx 32410 0.0 0.0 15964 980 pts/31 S+ 19:30 0:00 grep --color=auto a.out