linux下wait、waitpid和waitid的用法

1.函数原型

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

2.wait函数

wait函数会一直处于阻塞状态,直到有一个子进程退出,并返回退出子进程的ID,存储返回状态到wstatus中。

调用成功返回子进程的进程id。

3.waitpid函数

waitpid函数可以指定需要等待退出的子进程ID,wait函数等价于waitpid(-1, &wstatus, 0);调用成功返回子进程的进程id。

waitpid各项参数的含义如下:

pid

  • 小于-1 等待所有组ID等于pid的子进程;
  • 等于-1 等待父进程创建的任何子进程;
  • 等于0 等待所有组id等于父进程组id的子进程;
  • 大于0,参数pid表示需要等待的子进程的ID;

options通常为0表示等待进程终止,也可以是以下宏

  • WNOHANG 如果没有子进程存在,立即返回,结束阻塞状态;
  • WCONTINUED 如果子进程在停止状态接收到了SIGCONT信号重新恢复运行,waitpid函数也立即返回;
  • WUNTRACED

4.waitid函数

waitid提供了更加丰富的选项,使用waitid可以实现wait和waitpid的所有功能,该函数调用成功返回0,并且会将子进程的信息存储在infop中,具体的参数如下:

idtype

  • P_PID 等待进程ID等于id的进程终止;
  • P_GID 等待任何进程组ID等于id的子进程终止
  • P_ALL 等待任何子进程的终止,只要有一个进程终止函数就会返回,这个时候第二个参数id无效;

如果infop不为NULL,则档waitid成功返回时,这个结构将会被填写,我们可以从该结构中获取我们感兴趣的信息,其中有:

  • si_pid: 子进程的进程id;
  • si_uid:子进程的真实用户id;
  • si_signo:总是设置为SIGCHID;
  • si_status:可以是子进程的退出状态,或者是造成子进程状态改变的原因,si_code用来解释这个字段;
  • si_code:可以是CLD_EXITED、CLD_KILLED、CLD_DUMPED、CLD_TRAPPED、CLD_CONTINUED,记录子进程状态改变的原因;

options

  • WEXITED 等待子进程被终止;
  • WSTOPPED 等待子进程停止,stoped状态可以恢复运行;
  • WCONTINUED 等待子进程从stoped状态恢复;
  • WNOHANG 如果没有子进程立即返回;
  • WNOWAIT 使子进程处于可等待状态,后续可以调用wait获取子进程的状态信息;

5.关于wait、waitpid、waitid接收子进程的返回值

  • wait和waitpid接收到的子进程的返回值存储在status中,waitid函数接收到的返回值存储在infop结构体的si_status中;
  • 这三个函数得到status的值之后直接使用printf打印出来,得到的结果与子进程实际return的值不同,需要使用WIFEXITED、WIFSIGNALED、WIFSTOPPED进一步解析,可以直接使用man waitpid在ubuntu下查看详细信息;

5、示例代码

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
/*在main函数中创建3个进程,分别使用wait、waitpid、waitid等待子进程退出*/
void check_exit_status(int status)
{
	if(WIFEXITED(status))//如果子进程退出,使用WEXITSTATUS获取子进程的return值
	{
		printf("子进程返回信息码:%d\n",WEXITSTATUS(status));
	}else if(WIFSIGNALED(status))//如果子进程被信号打断,使用WTERMSIG获得对应信号的值
	{
		printf("子进程信号中断返回信息码:%d\n",WTERMSIG(status));
	}else if(WIFSTOPPED(status))//如果子进程被停止,使用WSTOPSIG获得对应的信号的值
	{
		printf("子进程暂停返回信息码:%d\n",WSTOPSIG(status));
	}else
	{
		printf("其他退出信息!\n");
	}
}
int value = 0;
int main(int argc,char *argv[])
{
	int ret = -1;
	int status;
	siginfo_t info;
	pid_t pid = 0;
    pid_t pid1 = 0;
	pid_t pid2 = 0;
	pid_t pid3 = 0;
	pid1 = fork();
    if(pid1 == 0)
	{
		sleep(1);
		while(1)
		{
			printf("child1 process pid %u,value=%d\r\n",getpid(),value);
			value++;
			//sleep(1);
			if(value == 5)break;
		}
		//exit(3);
		return 3;
	}
	else
	{
	    pid2 = fork();
		if(pid2 == 0)
	    {
			sleep(2);
			while(1)
			{
				printf("child2 process pid %u,value=%d\r\n",getpid(),value);
				value++;
				//sleep(1);
				if(value == 5)break;
			}
			//exit(4);
			return 4;
	    }
		else
		{
	        pid3 = fork();
			if(pid3 == 0)
			{
				sleep(3);
				while(1)
				{
					printf("child3 process pid %u,value=%d\r\n",getpid(),value);
					value++;
					//sleep(1);
					if(value == 5)break;
				}
				//exit(5);
				return 5;
			}
			else
			{
				printf("waiting for child progress exit!\r\n");
				//指定等待进程2退出
				pid = waitpid(pid2,&status,0);
				printf("child %u exit\r\n",pid,status);
				check_exit_status(status);
				//只要有一个进程终止就会解除阻塞
				ret = waitid(P_ALL,0,&info,WEXITED);
				if(0 == ret)
					printf("child %u exit,status = %d,code = %d\r\n",info.si_pid,info.si_status,info.si_code);
				check_exit_status(info.si_status);
				//任何进程退出都会解除wait阻塞
				pid = wait(&status);
				printf("child %u exit,status = %d\r\n",pid,status);
				check_exit_status(status);
			}
		}
	}

	

}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值