wait和waitpid函数

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

调用wait或waitpid的进程可能会发生的情况: 

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

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

3.如果它没有任何子进程,则立即出错返回


一、函数声明

1.wait函数

 pid_t wait(int *status);     

1) 返回值:成功返回被等待进程pid,失败返回-1。     

2) 参数: 输出型参数,获取子进程退出状态,不关心则可以设置成为NULL 

2. waitpid函数

 pid_t waitpid(pid_t pid, int *status, int options);     

1) 返回值:         

a. 当正常返回的时候waitpid返回收集到的子进程的进程ID;         

b. 如果设置了选项WNOHANG, 而调用中waitpid发现没有已退出的子进程可收集, 则返回0;         

c. 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;       

d. 当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD.     

2) 参数:         

a.  pid:

Pid=-1,等待任一个子进程。与wait等效;  Pid>0,等待其进程ID与pid相等的子进程;Pid==0等待其组ID等于调用进程组ID的任一个子进程;Pid<-1等待其组ID等于pid绝对值的任⼀一⼦子进程。        

b.  status:           

 WIFEXITED(status)  : 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)  

 WEXITSTATUS(status) : 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码) 

 WIFSIGNALED(status) 若为子进程异常终止返回状态(收到一个未捕捉的信号),则为真  

 WIFSTOPPED 若为子进程意外终止,则为真      

 c.  options:            

 WNOHANG :若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。 若正常结束,则返回该子进程的ID。 

WUNTRACED: 若某个实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。

3. status意义

status指出了子进程是正常退出还是被非正常结束的(一个进程也可以被其他进程用信号结束),以及正常结束时的返回值,或被哪一个信号结束或进程的退出码是多少等信息,这些信息都被放在整数的不同二进制位中,status的低8位为零,次低8位为真正退出码。

二、wait函数和waitpid函数的区别:

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

2. waitpid并不等待第一个终止的子进程-----它有若干个选项,可以控制它所等待的进程。

3. waitpid函数等待一个特定的进程,而wait则返回任一终止子进程的状态。

4.waitpid提供了一个wait的非阻塞版本。

5.waitpid支持作业控制。

三、一些实例

1.进程的阻塞等待方式

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

int main()
{
	pid_t pid;
	pid = fork();
	if(pid < 0)
	{
		printf("%s fork error\n", __FUNCTION__);
		return 1;
	}
	else if(pid == 0)
	{
		printf("child is run, pid is: %d\n", getpid());
		sleep(3);
		exit(257);
	}
	else
	{
		int status = 0;
		pid_t ret = waitpid(-1, &status, 0); //阻塞式等待
		printf("this is test for wait\n");
		if(WIFEXITED(status) && ret == pid) // WIFEXITED(status): 若为正常终止子进程返回的状态,则为真.(查看进程是否是正常退出) 
		{
			printf("wait child  success, child return code is: %d\n", WEXITSTATUS(status)); // WEXITSTATUS(status): 若WIFEXITED非0,提取子进程退出码.(查看进程的退出码)
		}
		else
		{
			printf("wait child failed, return.\n");
			return 1;
		}
	}
	return 0;
}
运行结果:


2. 进程的非阻塞等待方式

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

int main()
{
	pid_t pid;
	pid = fork();
	if(pid < 0)
	{
		printf("%s fork error\n", __FUNCTION__);
		return 1;
	}
	else if(pid == 0)
	{
		printf("child is running, pid is: %d\n", getpid());
		sleep(5);
		exit(1);
	}
	else
	{
		int status = 0;
		pid_t ret = 0;
		do
		{
			ret = waitpid(-1, &status, WNOHANG); //非阻塞等待
			if(ret == 0)
			{
				printf("child is running\n");
			}
			sleep(1);
		}while(ret == 0);
		if(WIFEXITED(status) && ret == pid)
		{
			printf("wait child success, child return code is: %d\n",WEXITSTATUS(status));
		}
		else
		{
			printf("wait child failed,return.\n");
			return 1;
		}
	}
	return 0;
}

运行结果:


3. 等待多个子进程方式

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

#define _PROC_NUM_ 10
#define _DEFAULT_PID_ -1

int child_run()
{
	srand(time(NULL));
	int _time = rand()%30;
	printf("this child pid is: %d, sleep time is: %d\n", getpid(), _time);
	sleep(_time);
	return 0;
}

int creat_proc(pid_t *pid, int num)
{
	if(pid != NULL && num > 0)
	{
		int i = 0;
		for(; i < num; i++)
		{
			pid_t id = fork();
			if(id < 0)
			{
				printf("%s: creat %d proc failed\n", __FUNCTION__, i);
				return 1;
			}
			else if(id == 0)
			{
				int child_ret = child_run();
				exit(1);
			}
			else
			{
				pid[i] = id;
			}
		}
	}
	return 0;
}

int wait_proc(pid_t *pid, int num)
{
	int wait_ret = 0;
	if(pid != NULL && num > 0)
	{
		int i = 0;
		for(; i < num; i++)
		{
			if(pid[i] == _DEFAULT_PID_)
			{
				continue;
			}
			int status = 0;
			int ret = waitpid(pid[i], &status, 0);
			if(WIFEXITED(status) && ret == pid[i])
			{
				printf("wait child pid %d success, return code is: %d\n", pid[i], WEXITSTATUS(status));
			}
			else
			{
				printf("wait child pid %d failed\n", pid[i]);
				wait_ret = 1;
			}
		}
	}
	return wait_ret;
}
//wait子进程传入的status,它的低8位为零,次低8位为真正退出码.

int main()
{
	pid_t pid_list[_PROC_NUM_];
	int i = 0;
	for(; i < _PROC_NUM_; i++)
	{
		pid_list[i] = _DEFAULT_PID_;
	}
	if(creat_proc(pid_list, sizeof(pid_list)/sizeof(pid_list[0])) == 0)
	{
		printf("%s: create all proc successs!\n", __FUNCTION__);
	}
	else
	{
		printf("%s: not all proc create success!\n", __FUNCTION__);
	}

	if(wait_proc(pid_list, sizeof(pid_list)/sizeof(pid_list[0])) == 0)
	{
		printf("%s: wait all proc success!\n", __FUNCTION__);
	}
	else
	{
		printf("%s: not all proc wait success!\n", __FUNCTION__);
	}

	return 0;
}

运行结果:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值