进程在自己的生命周期中,会处于不同的状态,其所处的状态会随着一些触发条件发生转变。使用ps
和top
等命令查看进程信息时,可以看到关于进程状态的相关信息,通常是在名为S
的一列中使用进程状态码(PROCESS STATE CODES)表示。
在ps的文档中,PROCESS STATE CODES相关的描述如下:
1 | PROCESS STATE CODES |
我们比较关注的几个状态是:D、R、S、T、Z,它们的转移关系如下:

回收子进程
当一个进程由于某种原因终止时,内核并不是立即把它从系统中清除。相反,进程被保持在一种已终止的状态(Z, zombie)中,直到进程被其父进程回收。当父进程回收已经终止的子进程时,内核将子进程的退出状态传递给父进程,然后抛弃已经终止的进程,从此时起,该进程就不存在了。
如果一个父进程在回收子进程之前就终止了,子进程将会挂到init进程下,被init进程领养,由init进程进行回收。init进程的pid为1,在系统初始化时由内核创建。
一个进程可以通过调用waitpid函数来等待其子进程终止或者停止。wait函数是waitpid的简单版,wait(&status)等价于调用waitpid(-1, &status, 0).
waitpid:
1 | #include <sys/types.h> |
waitpid会挂起调用它的进程直到由pid参数指定的等待集合中的一个子进程已更改状态。默认情况下,waitpid()只等待已终止的子进程,但是这个行为可以通过options参数修改。
waitpid的返回,一共有3种情况:
- 当正常返回的时候,waitpid返回收集到的子进程的进程ID;
- 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
- 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid的值可以是:
<-1 表示等待进程组ID等于pid的绝对值的任意子进程;
-1 表示等待任意子进程;
0 表示等待其进程组ID为调用进程的pid的任意子进程;
> 0 表示等待进程ID为pid的子进程;
int *status:
如果参数status的值不是NULL,wait就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程是正常退出还是被非正常结束的(一个进程也可以被其他进程用信号结束,我们将在以后的文章中介绍),以及正常结束时的返回值,或被哪一个信号结束的等信息。由于这些信息被存放在一个整数的不同二进制位中,所以用常规的方法读取会非常麻烦,人们就设计了一套专门的宏(macro)来完成这项工作:
WIFEXITED(status) 如果子进程正常结束,它就返回真;否则返回假。
WEXITSTATUS(status) 如果WIFEXITED(status)为真,则可以用该宏取得子进程exit()返回的结束代码。
WIFSIGNALED(status) 如果子进程因为一个未捕获的信号而终止,它就返回真;否则返回假。
WTERMSIG(status) 如果WIFSIGNALED(status)为真,则可以用该宏获得导致子进程终止的信号代码。
WIFSTOPPED(status) 如果当前子进程被暂停了,则返回真;否则返回假。
WSTOPSIG(status) 如果WIFSTOPPED(status)为真,则可以使用该宏获得导致子进程暂停的信号代码。
option:
option的值可以用来指定waitpid的行为,主要是指定在什么情况下予以返回。option的值是0或者以下参数的或值:
WNOHANG: 当没有子进程退出时,立即返回,返回值为0。默认的行为是挂起调用进程,直到有子进程终止。在等待子进程终止的同时,如果想执行一些其他的工作,可以使用此项。
WUNTRANCED:返回已终止(terminated, Z)和被停止(stopped, T)的进程。默认只返回已终止的(terminated)进程。
WCONTINUED (since Linux 2.6.10) : 当stopped 的子进程被SIGCONT信号唤醒时,也返回。
option组合:
WNOHANG|WUNTRANCED 表示 立即返回,如果等待集合中的子进程没有子进程被终止(terminated, Z)或者被停止(stopped, T),返回0,否则返回相应的pid。