进程退出
1 2 3 4 5
| #include <stdlib.h> void exit(int status);
#include <unistd.h> void _exit(int status);
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
#include <stdio.h> #include <stdlib.h> #include <unistd.h>
int main() {
printf("hello\n"); printf("world");
_exit(0);
return 0; }
|
孤儿进程
父进程运行结束,但子进程还在运行(未运行结束),这样的子进程就称为孤儿进程(Orphan Process).
每当出现一个孤儿进程时候,内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()(进程资源释放)它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作
因此孤儿进程并不会有什么危害。
对比代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
#include <stdio.h> #include <sys/types.h> #include <unistd.h>
int main() {
pid_t pid = fork();
if(pid > 0) {
printf("i am parent process, pid : %d, ppid : %d\n", getpid(), getppid());
} else if(pid == 0) { printf("i am child process, pid : %d, ppid : %d\n", getpid(), getppid()); sleep(1); }
for(int i = 0; i < 3; i++) { printf("i : %d, pid : %d\n", i, getpid()); }
return 0; }
|
注意 pid、ppid 变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
#include <stdio.h> #include <sys/types.h> #include <unistd.h>
int main() {
pid_t pid = fork();
if(pid > 0) {
printf("i am parent process, pid : %d, ppid : %d\n", getpid(), getppid());
} else if(pid == 0) { sleep(1); printf("i am child process, pid : %d, ppid : %d\n", getpid(), getppid()); }
for(int i = 0; i < 3; i++) { printf("i : %d, pid : %d\n", i, getpid()); }
return 0;
|
僵尸进程
每个进程结束之后,都会释放自己地址空间中的用户区数据,内核区的 PCB没有办法自己释放掉,需要父进程去释放。
进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸( zombie)进程。
僵尸进程不能被kill -9杀死。
这样就会导致一个问题,如果父进程不调用wait()或waitpid()的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的, 如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
#include <stdio.h> #include <sys/types.h> #include <unistd.h>
int main() {
pid_t pid = fork();
if(pid > 0) { while(1) {
printf("i am parent process, pid : %d, ppid : %d\n", getpid(), getppid()); sleep(1);
} } else if(pid == 0) { printf("i am child process, pid : %d, ppid : %d\n", getpid(), getppid()); }
for(int i = 0; i < 3; i++) { printf("i : %d, pid : %d\n", i, getpid()); }
return 0; }
|
新打开一个窗口 ps aux 查看进程 可以试着用 kill -9 进程id (测试杀死僵尸进程)
如果父进程结束了 子进程就会被进程为 1 的接替

进程回收
在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要主要指进程控制块PCB的信息(包括进程号、退出状态、运行时间等)。
父进程可以通过调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程。
wait()和waitpid()函数的功能一样,区别在于, wait()函数会阻塞,waitpid ()可以设置不阻塞, waitpid()还可以指定等待哪个子进程结束。
注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。