函数wait和waitpid

当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件。所以这种信号也是内核向父进程发的异步通知。父进程可以选择忽略该信号,或者提供一个该信号发生时即使被调用执行的函数。对于这种信号的系统默认动作时忽略它。对于wait和waitpid函数。

如果其所有子进程都还在运行,则阻塞。

如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。

如果它没有任何子进程,则立即出错。

如果进程由于接收到SIGCHLD信号而调用wait,我们期望wait会立即返回。但是如果在随机时间点调用wait,则进程可能会阻塞。

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

这两个函数的区别如下:

在一个子进程终止前,wait使其调用者阻塞,而waitpid有一选项,可使调用者不阻塞。

waitpid并不等待在其调用之后的第一个终止子进程,它有若干个选项,可以控制它所等待的进程。

如果子进程已经终止,并且是一个僵死进程,则wait立即返回并取得该子进程的状态。否则则wait使其调用者阻塞,直到一个子进程终止。如调用者阻塞而且它有多个子进程,则在其某一个子进程终止时,wait就立即返回。因为wait返回终止子进程的进程ID,所以它总能了解是哪一个子进程终止了。

这两个函数的参数statloc是一个整型指针。如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内。如果不关心终止状态,则可将该参数指定为空指针。

依据传统,这两个函数返回的整型状态字是由实现定义的。其中某些为表示退出状态,其他位则指示信号编号,有一位指示是否产生了core文件等。POSIX.1规定,终止状态用定义在<sys/wait.h>中的各个宏来查看。有4个互斥的宏可用来取的进程终止的原因,它们的名字都以WIF开始。基于这4个宏中哪一个值为真,就可选其他宏来取得退出状态、信号编号等。这4个互斥的宏表示于下图:

说明

WIFEXITED(status)

若为正常终止子进程返回的状态,则为真。对于这种情况可执行WEXITSTATUS(status),获取子进程传送给exit或_exit参数的低8位

WIFSIGNALED(status)

若为异常终止子进程返回的状态,则为真。对于这种情况,可执行WTERMSIG(status),获取使子进程终止的信号编号。另外,有些实现定义宏WCOREDUMP(status),若已产生终止进程的core文件,则它返回真

WIFSTOPPED(status)

若为当前暂定子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(status),获取使子进程暂停的信号编号

WIFCONTINUEO(status)

若在作业控制暂停后已经继续的子进程返回了状态,则为真,仅用于waitpid


实例:

#include "apue.h"
#include <sys/wait.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;
	if((pid = fork()) < 0)
		err_sys("fork error");
	else if(pid == 0)
		exit(7);
	
	if(wait(&status) != pid)
		err_sys("wait error");
	pr_exit(status);
	
	if((pid = fork()) < 0)
		err_sys("fork error");
	else if(pid == 0)
		abort();
	
	if(wait(&status) != pid)
		err_sys("wait error");
	pr_exit(status);
	
	if((pid = fork()) < 0)
		err_sys("fork error");
	else if(pid == 0)
		status /=0;
	
	if(wait(&status) != pid)
		err_sys("wait error");
	pr_exit(status);
	
	exit(0);
}
运行程序:

# ./a.out 
normal termination, exit status = 7
abnormal termination, signal number = 6
abnormal termination, signal number = 8
我们从WTERMSIG中打印信号编号。可以查看<signal.h>头文件验证SIGABRT的值为6,SIGFPE的值为8.

正如前面所述,如果一个进程有几个子进程,那么只要有一个进程终止,wait就返回。POSIX.1定义了waitpid函数用于等待一个指定的进程终止,对于waitpid函数中pid参数的作用解释如下。

pid == -1 等待任一子进程。此种情况下,waitpid与wait等效。

pid >0  等待进程ID与pid相等的子进程。

pid == 0 等待组ID等于调用进程组ID的任一子进程。

pid < -1 等待组ID等于pid绝对值的任一子进程。

waitpid函数返回终止子进程的进程ID,并将该子进程的终止状态放在由statloc指向的存储单元中。对于wait,其唯一的出错是调用进程没有子进程。但是对于waitpid,如果指定的进程或进程组不存在,或者参数pid指定的进程不是调用进程的子进程,都可能出错。

options参数使我们能进一步控制waitpid的操作,此参数或者时0,或者是下表的常量值按或运算的结果。

常量

说明

WCONTINUED

若实现支持作业控制,那么由pid制定的任一子进程在停止后已经继续,但其状态尚未报告,则返回其状态

WNOHANG

若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0

WUNTRACED

若某实现支持作业控制,而由pid指定的任一子进程已处于停止状态,并且其状态自停止以来还未报告过,则返回其状态,WIFSTOPPED宏确定返回值是否对应于一个停止的子进程。

waitpid函数提供了wait函数没有提供的3个功能。

(1)waitpid可等待一个特定的进程,而wait则返回任一终止子进程的状态。

(2)waitp提供了一个wait的非柱塞版本。有时希望获取一个子进程的状态,但不想阻塞。

(3)waitpid通过WUNTRACED和WCONTINUED选项支持作业控制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值