wait 和 waitpid 函数

当一个进程正常终止或异常终止时,内核就会向其父进程发送 SIGCHLD 信号,父进程对这种信号的默认动作是忽略它。可以使用 wait 和 waitpid 函数来获取子进程的终止状态。

#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
/* 两个函数返回值:若成功,返回进程 ID;否则,返回 0 或 -1 */

通常调用这两个函数时:
* 如果其所有子进程都还在运行,则阻塞。
* 如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态后立即返回。
* 如果它没有任何子进程,则立即出错返回。
这两个函数的区别如下。
(1)在一个子进程终止前,wait 使其调用者阻塞,而 waitpid 有一选项可使调用者不阻塞。
(2)waitpid 并不一定要等待在其调用之后的第一个终止子进程,它有若干个可以控制它所等待的进程的选项。
(3)对于 wait,其唯一的出错是调用进程没有子进程(函数调用被一个信号中断时也可能返回另一种出错)。但对于 waitpid,如果指定的进程或进程组不存在,或者 pid 指定的进程不是调用进程的子进程,都可能出错。
它们的参数 statloc 如果不是一个空指针,则子进程的终止状态就存放在它所指向的单元内。如果不关心终止状态,则可将其指定为空指针。依照传统,返回的整型状态字是由实现定义的,其中某些位表示退出状态(正常返回),其他位则指示信号编号(异常返回),有一位指示是否产生了 core 文件等。终止状态可用 <sys/wait.h> 中的各个宏来查看,下表中 4 个互斥的宏可用来取得进程终止的原因。基于这 4 个宏中哪一个为真,就可选用其它宏来取得退出状态、信号编号等(很多平台都支持 WCOREDUMP 宏,但如果定义了 _POSIX_C_SOURCE 常量,有些平台就隐藏该定义)。
[img]http://dl2.iteye.com/upload/attachment/0126/7358/ea409828-d4c7-3471-bddf-6f8eaf5782c4.png[/img]
下面这个程序就是利用这 4 个宏来打印进程终止状态的说明。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

void pr_exit(int status){
if(WIFEXITED(status))
printf("normal terminaltion, 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;

if((pid=fork()) < 0){
printf("1st fork error\n");
exit(2);
}else if(pid == 0) // child
exit(7);
if(wait(&status) != pid){ // wait for child
printf("1st wait error\n");
exit(2);
}
pr_exit(status); // and print its status

if((pid=fork()) < 0){
printf("2nd fork error\n");
exit(2);
}else if(pid == 0)
abort(); // generates SIGABRT, signal number is 6
if(wait(&status) != pid){
printf("2nd wait error\n");
exit(2);
}
pr_exit(status);

if((pid=fork()) < 0){
printf("3rd fork error\n");
exit(2);
}else if(pid == 0)
status /= 0; // generates SIGFPE, signal number is 8
if(wait(&status) != pid){
printf("3rd wait error\n");
exit(2);
}
pr_exit(status);

exit(0);
}

运行结果如下。

$ ./exitStatusDemo.out
normal terminaltion, exit status = 7
abnormal termination, signal number = 6(core file generated)
abnormal termination, signal number = 8(core file generated)
$

如果一个进程有几个子进程,那么只要有一个子进程终止,wait 就返回。如果要等待一个指定的进程终止,waitpid 函数就派上用场了。对于 waitpid 函数中的 pid 参数的作用解释如下。
* pid == -1:等待任一子进程,此时等效于 wait。
* pid > 0:等待进程 ID 为 pid 的子进程。
* pid == 0:等待组 ID 等于调用进程组 ID 的任一子进程。
* pid < -1:等待组 ID 等于 pid 绝对值的任一子进程。
参数 options 可以进一步控制 waitpid 的操作。此参数可以为 0 或者是下表中各常量按位或运算的结果(FreeBSD 8.0 和 Solaris 10 支持另一个非标准的可选常量 WNOWAIT,它使系统将终止状态已由 waitpid 返回的进程保持在等待状态,这样它可被再次等待)。
[img]http://dl2.iteye.com/upload/attachment/0126/7364/4a66898d-5e1d-3475-b4e0-d5df131213bc.png[/img]
如果一个进程 fork 了一个子进程,但不要它等待子进程终止,也不希望子进程处于僵死状态直到父进程终止,实现这一要求的诀窍就是调用 fork 两次,正如下列这个程序所示。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void){
pid_t pid;

if((pid=fork()) < 0){
printf("1st fork error\n");
exit(2);
}else if(pid == 0){ // first child
if((pid=fork()) < 0){
printf("2nd fork error\n");
exit(2);
}else if(pid > 0){
exit(0); // parent from second fork == first child
}

/* We're the second child; our parent becomes init as soon as
* our real parent calls exit() in the statement above. Here's
* where we'd continue executing, knowing that when we're
* done, init will reap our status.
*/
sleep(2);
printf("second child, parent pid=%ld\n", (long)getppid());
exit(0);
}

if(waitpid(pid, NULL, 0) != pid){ // wait for first child
printf("waitpid error\n");
}

/* We're the parent(the original process); we continue executing,
* knowing that we're not the parent of the second child.
*/
exit(0);
}

执行结果:

$ ./fork2timesDemo.out
$ second child, parent pid = 1

注意,这里当原先的进程(即 exec 本程序的进程)终止时,shell 打印其提示符,因为这在第二个子进程打印其父进程 ID 之前发生。
另外,Single UNIX Specification 包含了另一个取得进程终止状态的函数----waitid,此函数类似于 waitpid,但提供了更多的灵活性。

#include <sys/wait.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
/* 返回值:若成功,返回 0;否则,返回 -1 */

waitid 也允许一个进程指定要等待的子进程,但它使用两个单独的参数表示要等待的进程所属的类型,而不是将此与进程 ID 或进程组 ID 组合成一个参数。id 参数的作用与 idtype 的值相关。该函数支持下表中的这几个 idtype 类型。
[img]http://dl2.iteye.com/upload/attachment/0126/7559/1a89d562-460e-3720-9863-5177f0a0c5f5.png[/img]
options 参数是下表中各标志的按位或运算,这些标志指示调用者关注哪些状态变化。
[img]http://dl2.iteye.com/upload/attachment/0126/7561/c6a862d7-e73f-3715-9d13-d1dd0badf3d8.png[/img]
注意,WCONTINUED、WEXITED 和 WSTOPPED 这 3 个常量之一必须指定。
infop 参数是指向 siginfo 结构的指针,该结构包含了造成子进程状态改变有关信号的详细信息。
大多数 UNIX 系统实现还提供了 wait3 和 wait4 函数,它们提供的功能比上面几个 wait 函数提供的要多一个,这与附加参数有关,该参数允许内核返回由终止进程及其所有子进程使用的资源情况。资源统计信息(不同于资源限制)包括用户 CPU 时间总量、系统 CPU 时间总量、缺页次数、接收到信号的次数等,有关细节可查阅 getrusage(2) 手册页。

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>

pid_t wait3(int *statloc, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);
/* 两个函数返回值:若成功,返回进程 ID;否则,返回 -1 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值