Outline
- 1.僵尸进程
- 2.wait/waitpid
- 3.如何避免僵尸进程
=================================================================================================
1. 僵尸进程
在认识进程一文中,讲到过进程共有5种正常的退出方式以及3种异常的终止方式。现在考虑两种情况:
a)子进程在父进程之前结束
若子进程在父进程之前结束,那么操作系统将会为该子进程保存一定的信息,以便父进程在需要的时候进行查询(wait/waitid函数)。处于此种状态的子进程称为“僵尸进程”,即作为进程主体的堆、栈等地址空间已经被释放,仅仅在系统中留有一些信息。
b)父进程在子进程之前结束
若父进程在子进程之前结束,则子进程就变成了可怜的“孤儿进程”,这时候unix系统的“超级奶爸”进程init
,即pid为1的进程便会来收养他们,成为他们的父进程。具体过程为:当任一进程结束时,内核便逐个检查所有活动进程,以判断是否是正要终止进程的子进程,如果是,则将该进程的父进程id更改为1,而1进程只有在系统退出时才会结束,所以他是一个非常可靠的老爸。
2. wait/waitpid
函数原型:
- #include <sys/wait.h>
- pid_t wait(int *statloc)
- pid_t waitpid(pid_t pid, int *statloc, int options)
说明:
statloc包含了子进程的终止状态,可以使用宏来检测:
- WIFEXITED(statloc)
-
WIFSIGNALED(statloc)
-
WIFSTOPPED(statloc)
-
WIFCONTINUED(statloc)
四个宏分别在子进程终止状态满足宏字面意思时,返回true
wait/waitpid函数的返回值会获取到终止信息的子进程的pid。
区别:
wait为阻塞调用,若没有子进程结束,则一直阻塞;否则返回第一个结束的子进程的状态信息。
waitpid可以在options参数中指定非阻塞模式WNOHANG,同时第一个参数pid可以指定获取特定子进程的退出信息。
- -1 此时与wait等效
-
>0 等待pid子进程
-
==0 相同组id任一子进程
-
<-1 组id为pid绝对值的任一子进程
3. 如何避免僵尸进程
僵尸进程存在的缺点主要是浪费系统资源,同时其进程id一直处于占用状态,不可以分配给新的进程,所以需要尽量避免。如果我们需要在当前进程中创建一个子进程,但是无法预知它什么时候会结束,又想确保它在任意情况下都不会变成僵尸进程,一种常用的方法是两次fork:
- #include <stdio.h>
-
#include <unistd.h>
-
#include <sys/wait.h>
-
#include <stdlib.h>
-
-
int main()
-
{
-
pid_t pid;
-
-
pid = fork();
-
if(pid < 0 ) {
-
printf("fork failed.\n");
-
} else if (pid == 0) {
-
printf("1st-child process: pid is %d, ppid is %d\n", getpid(), getppid());
-
pid = fork();
-
if(pid < 0)
-
printf("fork failed.\n");
-
else if(pid > 0) {
-
printf("2nd-parent process: pid is %d\n", getpid());
-
exit(0);
-
} else if(pid == 0) {
-
sleep(2);
-
printf("2nd-child process: pid is %d, ppid is %d\n", getpid(), getppid());
-
exit(0);
-
}
-
} else if (pid > 0) {
-
sleep(5);
-
printf("1st-parent process: pid id %d\n", getpid());
-
}
-
-
return 0;
-
}
运行结果:
- 1st-child process: pid is 4080, ppid is 4079
-
2nd-parent process: pid is 4080
-
2nd-child process: pid is 4081, ppid is 1
-
1st-parent process: pid id 4079
注意,fork并不确保子进程与父进程的执行顺序,sleep仅仅可以确保在大部分情况下程序中进程在父进程之前执行。
阅读(1516) | 评论(0) | 转发(0) |