什么是进程等待? 进程等待函数介绍:int wait(int *status); int waitpid(pid_ t pid, int *status, int option); 代码演示
什么是进程等待?
进程等待 : 等待子进程退出,获取子进程的退出码,释放子进程资源。
为什么要进行进程等待:避免子进程成为僵尸进程,僵尸进程会占用系统资源。如有很多,会严重影响服务器的性能;
僵尸进程 :子进程先于父进程退出,为了保存退出码,没有完全释放资源
进程等待分类 :
阻塞等待 : 为了完成一个功能,我们发起了一个调用,如果功能不能立即完成则一直等待
非阻塞等待 : 为了完成一个功能,我们发起了一个调用,如果功能不能立即完成则函数立即报错返回。
进程等待函数介绍
int wait(int *status);
功能 : 阻塞等待任意一个子进程的退出。意味着如果当前有子进程且都没有退出就会阻塞进程一直等待。
参数 : int *status 指针 status 指向的空间用于存放退出码
返回值 : 成功则返回处理的退出的子进程的pid (>0) , 失败则返回 -1 (比如没有子进程)
int waitpid(pid_ t pid, int *status, int option);
功能 : 也是等待子进程退出,但是可以等待指定的子进程,可以进行阻塞 / 非阻塞等待
参数 : pid_ t pid :指定等待的子进程pid , 若为 -1则表示等待任意一个子进程,
int *status :整形空间地址用于获取退出码
option :设置阻塞标志 0 表示阻塞等待 WNOHANG 表示非阻塞等待
返回值 : 大于0表示处理的退出子进程pid ; 等于0表示当前没有子进程退出(非阻塞) ; 小于0表示出错了;
代码演示
示例一
#include <stdio.h>
#include <sys/wait.h> //wait() waitpid()
int main()
{
printf("wait start ----------\n");
int status;
int ret = wait(&status);
//成功返回0 失败返回-1
if(ret<0){
perror("wait error");
//perror函数输出 “括号中字符串:上一个程序执行失败的原因”
return -1;
}
printf("wait end ----------\n");
return 0;
}
执行结果:
此时,由于父进程并没有属于自己的子进程,所以无法进行进程等待,返回 -1
示例二
#include <stdio.h>
#include<stdlib.h> //exit()
#include <unistd.h> //sleep() exit() fork()
#include <sys/wait.h> //wait() waitpid()
int main()
{
pid_t pid = fork();
if(pid < 0){
perror("fork error"); //打印fork执行失败的原因
return -1;
}else if (pid == 0){
sleep(3);
exit(99); //3秒后子进程退出
}
//能走下来的只有父进程
printf("wait start ----------\n");
int status;
int ret = wait(&status);//成功返回0 失败返回-1
//int ret = waitpid(-1,&status,0);与上行代码等价
if(ret < 0){
perror("wait error");
return -1;
}
printf("wait end ----------\n");
return 0;
}
程序立刻输出:
三秒后执行结果为 :
语句执行到wait( )处,开始进行进程阻塞等待,直到三秒后,子进程退出,等待退出。
示例三
#include<stdio.h>
#include<stdlib.h> //exit()
#include<unistd.h> //sleep() fork()
#include<sys/wait.h>
int main()
{
pid_t pid = fork(); //创建一个子进程
if(pid<0){
perror("fork error");
return -1;
}else if(pid == 0){
sleep(3);
exit(99);
}
printf("wait start ----------\n");
int status;
//当子进程存在,但并未退出时,
while(waitpid(-1,&status,WNOHANG) == 0){
printf("have child ,have not exited ,waiting...\n");
sleep(1);
}
printf("wait end ----------\n");
}
运行结果:
while中语句表示,当子进程存在但并未退出时,程序休眠一秒,一秒后再进行进程等待,直到子进程退出后,循环结束,进程等待也结束。
但如果子进程在休眠一秒中间退出,就意味着在下一次进程等待开始前,子进程成为了僵尸进程。
因此,我们可以得出结论:
wait / waitpid 并不是仅处理刚好退出的子进程,也会处理已经成为僵尸进程的子进程。
Status&退出码&异常信号
status是int类型,占四个字节,我们只用到后面两个字节,实际有效的也就是后两个字节
进程正常退出时,只用到后两个字节的高8位
进程异常退出时,只用到后两个字节的低8位,其中第八位是coredump标志位(核心转储,表示程序异常退出前将自己的运行信息保存起来,便于事后调试),低7位表示进程收到的终止信号。
程序崩溃的本质:程序运行的过程中发生异常,系统内核检测到后会给进程发送一个异常信号,程序崩溃异常退出。
只有进程的异常信号为0时,表示程序正常退出;否则就表示异常退出。
if (( status&0x7f) == 0){
printf("child exit code:%d\n",(status>>8) & 0xff);
}else{
printf("signal code:%d\n",status & 0x7f );
}
status & 0x7f 获取异常退出信号值
(status >> 8) & 0xff 获取退出码
实用接口:
if( WIFEXITED(status) ){
printf("child exit code : %d\n", WEXITSTATUS(status));
}