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退出即可。