1 wait/waitpid介绍
当一个进程正常或异常终止时,内核会向其父进程发送SIGCHLD信号。因为子进程终止是异步的,所以信号发送也是异步的。父进程可以选择忽略该信号,或者提供信号处理函数进行处理。对于SIGCHLD信号,系统默认动作是忽略它。
当父进程调用wait或waitpid时会发生什么:
(1)如果其所有子进程都还在运行,则阻塞。
(2)如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态后立即返回。
(3)如果其没有任何子进程,则立即出错返回。
#include <sys/wait.h>
// 返回值:若成功,返回子进程ID;若失败,返回0或0-1
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
1.1 wait
在子进程终止前,wait使父进程阻塞,而waitpid有一选项,可使父进程不阻塞。
参数statloc存放终止进程的终止状态,如果不关心终止状态,可以置为空指针。
有4个互斥的宏用来取得进程终止的原因,它们名字以WIF开始。
宏 | 说明 |
WIFEXITED(status) | 若为正常终止子进程返回的状态,则为真。 |
WIFSIGNALED(status) | 若为异常终止子进程返回的状态,则为真。对于这种情况,使用WTERMSIG(status)来获取使子进程终止的信号。 |
WIFSTOPPED(status) | 若为暂停子进程返回的状态,则为真。对于这种情况,使用WSTOPSIG(status)来获取使子进程暂停的信号。 |
1.2 waitpid
如果一个进程有多个子进程,只要一个子进程终止,wait就返回。如果要等待一个特定的进程终止,需要使用waitpid函数。
waitpid函数中pid参数有如下含义:
(1)pid == -1
等待任一子进程,这时waitpid与wait等效。
(2)pid > 0
等待进程ID与pid相等的子进程。
(3)pid ==0
等待组ID等于调用进程组ID的任一子进程。
(4)pid < -1
等待组ID等于pid绝对值的任一子进程。
waitpid函数返回终止子进程的进程ID,并将子进程的终止状态存放在由staloc指向的存储单元。
options参数说明:
常量 | 说明 |
WNOHANG | 若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时返回值为0 |
总结,waitpid函数相比wait函数:
(1)waitpid函数可等待一个特定的子进程终止
(2)waitpid提供了一个wait的非阻塞版本
2 使用wait函数获取子进程终止状态
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
void pr_exit(int status)
{
if (WIFEXITED(status))
printf("normal termination, exit status = %d\n",
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("abnormal termination, signal number = %d%s\n",
WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? " (core file generated)" : "");
#else
"");
#endif
else if (WIFSTOPPED(status))
printf("child stopped, signal number = %d\n",
WSTOPSIG(status));
}
int main(void)
{
pid_t pid;
int status;
// (1)子进程正常终止
if ((pid = fork()) < 0)
printf("fork error");
else if (pid == 0) /* child */
exit(7);
if (wait(&status) != pid) /* wait for child */
printf("wait error");
pr_exit(status); /* and print its status */
// (2)子进程异常终止 SIGABRT
if ((pid = fork()) < 0)
printf("fork error");
else if (pid == 0) /* child */
abort(); /* generates SIGABRT */
if (wait(&status) != pid) /* wait for child */
printf("wait error");
pr_exit(status); /* and print its status */
// (3)子进程异常终止 SIGFPE
if ((pid = fork()) < 0)
printf("fork error");
else if (pid == 0) /* child */
status /= 0; /* divide by 0 generates SIGFPE */
if (wait(&status) != pid) /* wait for child */
printf("wait error");
pr_exit(status); /* and print its status */
exit(0);
}
输出:
normal termination, exit status = 7
abnormal termination, signal number = 6 (core file generated)
abnormal termination, signal number = 8 (core file generated)
SIGABRT:6,SIGFPE:8。