Chinaunix首页 | 论坛 | 博客
  • 博客访问: 129349
  • 博文数量: 19
  • 博客积分: 508
  • 博客等级: 下士
  • 技术积分: 306
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-11 21:04
文章分类

全部博文(19)

文章存档

2011年(16)

2009年(3)

我的朋友

分类: LINUX

2011-07-15 12:11:11

Outline 

- 1.僵尸进程

- 2.wait/waitpid

- 3.如何避免僵尸进程

=================================================================================================

1. 僵尸进程
在认识进程一文中,讲到过进程共有5种正常的退出方式以及3种异常的终止方式。现在考虑两种情况:
a)子进程在父进程之前结束
若子进程在父进程之前结束,那么操作系统将会为该子进程保存一定的信息,以便父进程在需要的时候进行查询(wait/waitid函数)。处于此种状态的子进程称为“僵尸进程”,即作为进程主体的堆、栈等地址空间已经被释放,仅仅在系统中留有一些信息。

b)父进程在子进程之前结束
若父进程在子进程之前结束,则子进程就变成了可怜的“孤儿进程”,这时候unix系统的“超级奶爸”进程init
,即pid为1的进程便会来收养他们,成为他们的父进程。具体过程为:当任一进程结束时,内核便逐个检查所有活动进程,以判断是否是正要终止进程的子进程,如果是,则将该进程的父进程id更改为1,而1进程只有在系统退出时才会结束,所以他是一个非常可靠的老爸。

2. wait/waitpid
函数原型:
  1. #include <sys/wait.h>
  2. pid_t wait(int *statloc)
  3. pid_t waitpid(pid_t pid, int *statloc, int options)
说明:
statloc包含了子进程的终止状态,可以使用宏来检测:
  1. WIFEXITED(statloc)
  2. WIFSIGNALED(statloc)
  3. WIFSTOPPED(statloc)
  4. WIFCONTINUED(statloc)
四个宏分别在子进程终止状态满足宏字面意思时,返回true

wait/waitpid函数的返回值会获取到终止信息的子进程的pid。

区别:
wait为阻塞调用,若没有子进程结束,则一直阻塞;否则返回第一个结束的子进程的状态信息。
waitpid可以在options参数中指定非阻塞模式WNOHANG,同时第一个参数pid可以指定获取特定子进程的退出信息。
  1. -1 此时与wait等效
  2. >0 等待pid子进程
  3. ==0 相同组id任一子进程
  4. <-1 组id为pid绝对值的任一子进程

3. 如何避免僵尸进程
僵尸进程存在的缺点主要是浪费系统资源,同时其进程id一直处于占用状态,不可以分配给新的进程,所以需要尽量避免。如果我们需要在当前进程中创建一个子进程,但是无法预知它什么时候会结束,又想确保它在任意情况下都不会变成僵尸进程,一种常用的方法是两次fork:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/wait.h>
  4. #include <stdlib.h>

  5. int main()
  6. {
  7.   pid_t pid;
  8.   
  9.   pid = fork();
  10.   if(pid < 0 ) {
  11.     printf("fork failed.\n");
  12.   } else if (pid == 0) {
  13.     printf("1st-child process: pid is %d, ppid is %d\n", getpid(), getppid());
  14.     pid = fork();
  15.     if(pid < 0)
  16.       printf("fork failed.\n");
  17.     else if(pid > 0) {
  18.       printf("2nd-parent process: pid is %d\n", getpid());
  19.       exit(0);
  20.     } else if(pid == 0) {
  21.       sleep(2);
  22.       printf("2nd-child process: pid is %d, ppid is %d\n", getpid(), getppid());
  23.       exit(0);
  24.     }
  25.   } else if (pid > 0) {
  26.     sleep(5);
  27.     printf("1st-parent process: pid id %d\n", getpid());
  28.   }

  29.   return 0;
  30. }
运行结果:
  1. 1st-child process: pid is 4080, ppid is 4079
  2. 2nd-parent process: pid is 4080
  3. 2nd-child process: pid is 4081, ppid is 1
  4. 1st-parent process: pid id 4079
注意,fork并不确保子进程与父进程的执行顺序,sleep仅仅可以确保在大部分情况下程序中进程在父进程之前执行。


阅读(1516) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~