阻塞与非阻塞等待非阻塞轮询
目录
阻塞等待(Blocking Wait)
非阻塞等待(Non-blocking Wait)
非阻塞轮询
总结
进程等待所使用 waitpid 函数,有一个 options 参数,waitpid 函数的第三个参数用于指定父进程的等待方式:
0
:默认等待,阻塞直到一个子进程结束。WNOHANG
:非阻塞等待,如果没有任何子进程结束,则立即返回 0,不阻塞当前进程.若正常结束,则返回该子进程的 ID。WUNTRACED
:报告被跟踪的子进程(即使它们尚未停止)。WCONTINUED
:报告被继续执行的子进程(即被SIGCONT
信号继续执行)
阻塞等待(Blocking Wait)
阻塞等待意味着父进程会一直等待,直到子进程结束或出现错误为止。
通常使用 wait()
或带有默认选项的 waitpid()
函数实现(即 参数 options = 0
):waitpid(pid, &status, 0);
非阻塞等待(Non-blocking Wait)
非阻塞等待允许父进程在没有子进程结束的情况下继续执行其他任务。如果子进程未退出,父进程会直接读取子进程的状态并返回,然后接着执行后面的语句,不会等待子进程退出
通常使用带有 WNOHANG
选项的 waitpid()
函数实现(即 参数 options = WNOHANG
):waitpid(pid, &status, WNOHANG);
非阻塞轮询
轮询是指父进程在非阻塞式状态的前提下,以循环方式不断的对子进程进行进程等待,直到子进程退出。
例如,父进程可以隔一段时间调用一次waitpid函数,若是等待的子进程尚未退出,则父进程可以先去做一些其他事,过一段时间再调用waitpid函数读取子进程的退出信息:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void task1() {
printf("task1 is running...\n");
}
void task2() {
printf("task2 is runnning...\n");
}
int main() {
int id = fork();
if(id == -1) {
printf("fork error\n");
exit(-1);
} else if(id == 0) { //子进程
int cnt = 5;
while(cnt--) {
printf("子进程, pid:%d, ppid:%d, cnt:%d\n", getpid(), getppid(), cnt);
sleep(1);
}
exit(1);
} else { //父进程
int status = 0;
while(1) { //轮询
pid_t ret = waitpid(id, &status, WNOHANG); //非阻塞式等待
if(ret == -1) {
printf("wait fail\n"); //调用失败
exit(1);
} else if(ret == 0){ //调用成功,但子进程未退出
printf("wait success, but child process not exit\n");
task1(); //执行其他命令
task2();
} else { //调用成功,子进程退出
printf("wait success, and child exited\n");
break;
}
sleep(1);
}
if(WIFEXITED(status)) { //正常退出
printf("exit code:%d\n", WEXITSTATUS(status));
} else { //异常终止
printf("exit signal:%d\n",(status & 0x7f));
}
}
return 0;
}
运行结果就是,父进程每隔一段时间就去查看子进程是否退出,若未退出,则父进程先去忙自己的事情,过一段时间再来查看,直到子进程退出后读取子进程的退出信息。
总结
阻塞等待:先等你,我再继续
非阻塞等待:不等你,我继续做自己的事
非阻塞轮询:不等你,我继续做自己的事,期间不断看看你行没行