wait()
和waitpid()
系统调用wait()
用来等待任意子进程结束,参数为int*
,用来存放子进程的退出
状态,可以为NULL
。还有几个配套的宏来对子进程的退出状态进行判断,如WEXITSTATUS
等。用法如下面的例子:
1 |
|
如果父进程在创建完子进程后,没有对子进程的退出状态进行回收,而去处理其他工
作,就会使子进程变成僵尸进程。即,子进程退出,而父进程没有退出且没有回收子
进程的退出状态,子进程会成为僵尸进程。比如下面的例子:
wait3.c:1
2
3
4
5
6
7
8
9
10
11
12
13
int main(int argc, char *argv[])
{
if (fork()) {
while (1) {
sleep(3); /* 父进程不退出 */
}
} else {
exit(0); /* 子进程中直接退出 */
}
return 0;
}
运行如下:
1 | $ clang wait3.c -o wait3 |
可以看到 PID 为15371
的进程状态为Z
,即为僵尸进程。要避免这种情况发生,可
以使父进程将SIECHLD
信号的处理函数设置为忽略(SIG_IGN
)即可。
signal()
和kill()
这两个系统调用分别用来设置信号的处理函数和发送信号。signal()
的原型如下:
1 |
|
signal()
会接收要一个处理函数和对应的要处理的信号,返回值为调用signal()
前的该信号的处理函数指针。注册过处理函数后,进程再收到这个信号,系统就会回
调这个处理函数,并将收到的信号传递给这个处理函数。这样就可以将多个信号处理
函数注册为同一个函数,而在处理函数内部加以区分。
举例如下:
1 |
|
运行如下:
1 | $ clang signal.c -o signal |
另一个例子:
1 |
|
尝试用这种方式处理会产生僵尸进程的情况:
1 |
|
在 shell 里尝试以下操作:
1 | $ clang wait4.c -o wait4 |
此时再打开另一个 shell,输入以下内容:
1 | $ ps xo pid,ppid,state,session,command |
此时原来的 shell 会产生如下输出:
1 | $ clang wait4.c -o wait4 |
可以看到设置了信号处理函数被调用了,使用ps
命令也不会发现僵尸子进程。父进
程用Ctrl-c
退出即可。