1.基本概念
我们知道在Linux操作系统下,子进程的创建是通过父进程来完成的,同时子进程的结束和父进程运行是一个异步的过程,即父进程无法知道子进程什么时间推出, 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。
**僵尸进程:**当子进程退出后,它的父进程没有调用wite()或waitpid()获取子进程的退出信息,这个进程的各种信息依然保存在系统中,这种进程成为僵尸进程。
**孤儿进程:**一个父进程退出,但是它的一个或多个子进程依然在运行。这些进程被称之为孤儿进程,孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
问题及危害:
孤儿进程就是没有父进程的进程,内核将会出面将init进程设置位该进程的父进程,这时init就会循环的wait()直至该进程结束,由于有这个机制的存在,因此进程并不会有什么危害。
任何一个进程退出后(exit()),并不会立刻消失而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这时进程必须经过的一个状态,如果父进程没有及时处理,这个进程就会变成僵尸进程,我们知道系统维护这个数据结构时需要成本的,当有大量的僵尸进程时就会造成系统资源的大量浪费
//孤儿进程代码
#include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <unistd.h>
5
6 int main()
7 {
8 pid_t pid;
9 //创建一个进程
10 pid = fork();
11 //创建失败
12 if (pid < 0)
13 {
14 perror("fork error:");
15 exit(1);
16 }
17 //子进程
18 if (pid == 0)
19 {
20 printf("I am the child process.\n");
21 //输出进程ID和父进程ID
22 printf("pid: %d\tppid:%d\n",getpid(),getppid());
23 printf("I will sleep five seconds.\n");
24 //睡眠5s,保证父进程先退出
25 sleep(5);
26 printf("pid: %d\tppid:%d\n",getpid(),getppid());
27 printf("child process is exited.\n");
28 }
29 //父进程
30 else
31 {
32 printf("I am father process.\n");
33 //父进程睡眠1s,保证子进程输出进程id
34 sleep(1);
35 printf("father process is exited.\n");
36 }
37 return 0;
38 }
测试结果
这里ppid:1标识的就是init进程。
僵尸进程代码
#include <stdio.h>
2 #include <unistd.h>
3 #include <errno.h>
4 #include <stdlib.h>
5
6 int main()
7 {
8 pid_t pid;
9 pid = fork();
10 if (pid < 0)
11 {
12 perror("fork error:");
13 exit(1);
14 }
15 else if (pid == 0)
16 {
17 printf("I am child process.I am exiting.\n");
18 exit(0);
19 }
20 printf("I am father process.I will sleep two seconds\n");
21 //等待子进程先退出
22 sleep(2);
23 //输出进程信息
24 system("ps -o pid,ppid,state,tty,command");
25 printf("father process is exiting.\n");
26 return 0;
27 }
测试结果
可以看到进程状态已经发生改变Z。
僵尸进程的解决办法:
僵尸进程的产生是由于父进程没有及时处理退出的进程,因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个父进程解决掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。解决掉父进程之后,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。
解决讲述进程代码
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <signal.h>
6
7 static void sig_child(int signo);
8
9 int main()
10 {
11 pid_t pid;
12 //创建捕捉子进程退出信号
13 signal(SIGCHLD,sig_child);
14 pid = fork();
15 if (pid < 0)
16 {
17 perror("fork error:");
18 exit(1);
19 }
20 else if (pid == 0)
21 {
22 printf("I am child process,pid id %d.I am exiting.\n",getpid());
23 exit(0);
24 }
25 printf("I am father process.I will sleep two seconds\n");
26 //等待子进程先退出
27 sleep(2);
28 //输出进程信息
29 system("ps -o pid,ppid,state,tty,command");
30 printf("father process is exiting.\n");
31 return 0;
32 }
33
34 static void sig_child(int signo)
35 {
36 pid_t pid;
37 int stat;
38 //处理僵尸进程
39 while ((pid = waitpid(-1, &stat, WNOHANG)) >0)
40 printf("child %d terminated.\n", pid);
41 }