当一个进程正常或异常终止时,内核就向其父进程发送一个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;
}
运行结果: