子进程无论是正常或异常退出,内核都会向父进程发送信号 SIGCHILD.,因为无论是使用wait函数(阻塞),还是使用waitpid(得循环判断)都会将父进程阻塞住,而不能执行别的操作,所以,如果父进程还需要执行别的操作,就将wait/waitpid函数置于信号捕捉函数中就可以解决这个问题了,(当然也可以在父进程中单独起个线程来解决。)
wait函数、waitpid函数每次都只能回收一个子进程。
wait函数是通过waitpid函数封装的:
static inline pid_t wait(int * wait_stat)
{
return waitpid(-1,wait_stat,0);
}
1、区别1:返回值的区别
wait函数只有两个返回值,
成功返回回收的子进程id;
失败返回-1,errno被置为ECHILD。(调用进程没有子进程,调用就会失败,wait函数用这个条件来判断是否还有子进程没有回收),
waitpid函数的第三个参数设置为WNOHANG 时,返回值相较wait多了一种返回值,waitpid发现当前进程在运行,没有已退出的子进程可收集,则立即返回,返回值为0();当所有的子进程都已回收,则返回-1.(这一点与wait是一样的,同样可以根据这个参数来判断是否还有子进程没回收)
2、区别2:
wait函数会阻塞等待子进程的退出。
waitpid函数,当第三个参数使用WNOHANG时,无子进程退出,也会立刻返回(返回值为0)
3、回收多个子进程
使用waitpid来循环回收子进程(不需要知道子进程的数量)
方法一:使用信号,在捕捉函数中调用waitpid
此处使用了信号的形式来:
else if (pid > 0) {
Close(connfd);
signal(SIGCHLD,wait_child);
}
main函数外定义回调函数
void wait_child(int signo)
{
while(watipid(0,NULL,WNOHANG)>0); //大于0则继续回收
return;
}
方法二:直接在父进程中调用waitpid,参考该文。
while(1) /*无限循环保证所有子进程全部回收*/
{
pid_t wpid = waitpid(-1/*回收任何子进程*/, NULL, WNOHANG);
if(wpid == -1)
{
break; /*如果返回-1说明已经没有子进程了,退出循环*/
}
if(wpid > 0)
{
printf("wpid: %d\n", wpid); /*打印被回收的子进程的ID*/
}
}
//while循环中,没有使用sleep函数,也就是说,没有进程可回收,就立马返回。
//这个函数,其实还可以再加一句,
if(wpid==0)
continue;
使用wait函数来循环回收子进程(wait函数是阻塞进程的),参考该文
使用wait()回收多个子进程
首先使用wait()函数来回收多个子进程,我们可以在一个for循环中等待子进程的结束,创建了几个子进程就for循环等待几次,代码如下
/************************************************************
>File Name : mutipwait.c
>Author : Mindtechnist
>Company : Mindtechnist
>Create Time: 2022年05月20日 星期五 17时23分57秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char* argv[])
{
int i = 0;
pid_t pid;
for(i = 0; i < 5; i++)
{
pid = fork();
if(pid == 0)
{
printf("child: %d\n", getpid());
break;
}
}
sleep(i);
if(i == 5) /*只有父进程可以执行到i=5*/
{
for(i = 0; i < 5; i++)
{
pid_t wpid = wait(NULL);
printf("wpid: %d\n", wpid);
}
while(1)
{
sleep(1);
}
}
return 0;
}
//使用wait函数循环回收子进程是否也可以向waitpid一样,可以不知道进程个数呢?
这个待测试
while(wait(NULL)>0);