抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

进程退出

1
2
3
4
5
#include <stdlib.h>
void exit(int status);

#include <unistd.h>
void _exit(int status);

image-20220410190008070

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
/*************************************************************************
> File Name: exit.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年04月10日 星期日 19时08分41秒
************************************************************************/

/*

#include <stdlib.h>
void exit(int status);

#include <unistd.h>
void _exit(int status);
父进程回收子进程时候会用到!
status参数: 是进程退时的一个状态信息。父进程回收子进程资源时候可以h 获取到。

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {

printf("hello\n");
printf("world");

//exit(0); // 输出 hello world --- \n 会刷新缓冲区 吧缓冲区 world 输出到控制台
_exit(0); // 输出 hello

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
/*************************************************************************
> File Name: fork_exit.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年04月10日 星期日 21时12分28秒
************************************************************************/

#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
/*************************************************************************
> File Name: fork_exit.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年04月10日 星期日 21时12分28秒
************************************************************************/

#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
/*************************************************************************
> File Name: zombie.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年04月10日 星期日 21时12分28秒
************************************************************************/

#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 的接替

image-20220410225325329

进程回收

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

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

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

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

评论