小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 linux系列专栏<—请点击 倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己! 
目录
-
- 前言
- 一、进程等待的重要性
- 二、进程等待三个问题
-
- 进程等待是什么
- 为什么要有进程等待
- 进程等待是怎么做的
- 三、先看僵尸进程现象
- 四、wait
-
- 概念讲解
- wait的使用
- 阻塞状态
- 五、waitpid
-
- 概念讲解
- waitpid的使用
- waitpid获取子进程的退出信息
- waitpid等待指定的子进程
- waitpid等待多个子进程
- 六、非阻塞轮询
- 总结
前言
【linux】linux进程控制(一)(fork进程创建,exit进程终止)——书接上文 详情请点击<—— 本文由小编为大家介绍——【linux】linux进程控制(二)(进程等待)
本文与小编编写的【linux】linux进程概念(三)(进程状态,僵尸进程,孤儿进程,进程优先级)关联性较大,建议读者友友阅读后方蓝字链接的文章之后,基于后方蓝字链接文章的基础上再来学习本文文章详情请点击<——
一、进程等待的重要性
二、进程等待三个问题
进程等待是什么
为什么要有进程等待
进程等待是怎么做的
三、先看僵尸进程现象
//脚本代码
while :; do ps ajx | head –1 && ps ajx | grep testWait | grep –v grep; sleep 1; echo "—————————–"; done
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void RunChild()
{
int cnt = 3;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
pid_t id = fork();
if(id < 0)//创建子进程失败情况判断
{
perror("fork");//将错误码errno中对应的错误码转化为对应的字符串描述信息
return 1; //并且附带打印"fork"这个字符串,再返回退出码1表示错误
}
else if(id == 0)
{
RunChild();
exit(0);//在其他程序中,由于子进程和父进程代码共享所以子进程和父进程分流之后,我们不期望子进程执行父进程
//的那一部分代码,为了安全起见,我们不期望子进程执行后续代码
}//所以这里当子进程执行到这里的时候使用exit终止子进程
else
{
while(1)
{
printf("i am father process, pid: %d, ppid: %d\\n", getpid(), getppid());
sleep(1);
}
}
return 0;
}
运行结果如下 

四、wait
概念讲解

wait的使用
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void RunChild()
{
int cnt = 2;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
RunChild();
exit(0);
}
else
{
//id > 0
sleep(4);
int ret = wait(NULL);
if(ret == id)
{
printf("我是父进程,我等待子进程成功了, 子进程的pid: %d\\n", ret);
}
else
{
printf("等待子进程失败\\n");
}
sleep(2);
}
return 0;
}
运行结果如下
我们可以观察到前2秒子进程和父进程都在运行,然后过了两秒,子进程退出,由于父进程此时在休眠,无暇等待子进程,所以子进程此时会成为僵尸进程,再过两秒,父进程休眠完成,此时等待子进程成功,那么此时子进程的资源就被释放了,子进程被回收,父进程等待子进程完成后,小编将父进程设置成休眠2秒,所以此时会观察到只有父进程在运行的场景
阻塞状态
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void RunChild()
{
int cnt = 2;
while(1)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
RunChild();
exit(0);
}
else
{
//id > 0
//sleep(4);
int ret = wait(NULL);
if(ret == id)
{
printf("我是父进程,我等待子进程成功了, 子进程的pid: %d\\n", ret);
}
else
{
printf("等待子进程失败\\n");
}
sleep(2);
}
return 0;
}
运行结果如下 
五、waitpid
概念讲解

waitpid的使用
//脚本代码
while :; do ps ajx | head –1 && ps ajx | grep testWait | grep –v grep; sleep 1; echo "—————————–"; done
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void RunChild()
{
int cnt = 2;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
RunChild();
exit(0);
}
else
{
//id > 0
sleep(4)
int ret = waitpid(–1, NULL, 0);
if(ret == id)
{
printf("我是父进程,我等待子进程成功了, 子进程的pid: %d\\n", ret);
}
else
{
printf("等待子进程失败\\n");
}
sleep(2);
}
return 0;
}
运行结果如下
我们可以观察到前2秒子进程和父进程都在运行,然后过了两秒,子进程退出,由于父进程此时在休眠,无暇等待子进程,所以子进程此时会成为僵尸进程,再过两秒,父进程休眠完成,此时等待子进程成功,那么此时子进程的资源就被释放了,子进程被回收,父进程等待子进程完成后,小编将父进程设置成休眠2秒,所以此时会观察到只有父进程在运行的场景
waitpid获取子进程的退出信息
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void RunChild()
{
int cnt = 2;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
RunChild();
exit(2);
}
else
{
//id > 0
sleep(4);
int status = 0;
int ret = waitpid(–1, &status, 0);
if(ret == id)
{
printf("我是父进程,我等待子进程成功了, 子进程的pid: %d, 子进程的退出码为: %d\\n", ret, status);
}
else
{
printf("等待子进程失败\\n");
}
sleep(2);
}
return 0;
}
运行结果如下 


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void RunChild()
{
int cnt = 2;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
RunChild();
exit(2);
}
else
{
//id > 0
sleep(4);
int status = 0;
int ret = waitpid(–1, &status, 0);
if(ret == id)
{
printf("我是父进程, 我等待子进程成功了, 子进程的pid: %d, 退出信号为: %d, 子进程的退出码为: %d\\n", ret, status & 0x7F, (status >> 8) & 0xFF);
}
else
{
printf("等待子进程失败\\n");
}
sleep(2);
}
return 0;
}
运行结果如下
此时我们的退出信号和退出码就可以正常提取出来了
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void RunChild()
{
int cnt = 2;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
RunChild();
exit(2);
}
else
{
//id > 0
sleep(4);
int status = 0;
int ret = waitpid(–1, &status, 0);
if(ret == id)
{
printf("我是父进程,我等待子进程成功了\\n");
if(WIFEXITED(status))
{
printf("子进程的代码是正常跑完的, 子进程的pid: %d, 子进程的退出码为: %d\\n", ret, WEXITSTATUS(status));
}
else
{
printf("子进程出现异常\\n");
}
}
else
{
printf("等待子进程失败\\n");
}
sleep(2);
}
return 0;
}
运行结果如下 
waitpid等待指定的子进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void RunChild()
{
int cnt = 2;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
RunChild();
exit(2);
}
else
{
//id > 0
sleep(4);
int status = 0;
int ret = waitpid(id, &status, 0);
if(ret == id)
{
printf("我是父进程,我等待子进程成功了\\n");
if(WIFEXITED(status))
{
printf("子进程的代码是正常跑完的, 子进程的pid: %d, 子进程的退出码为: %d\\n", ret, WEXITSTATUS(status));
}
else
{
printf("子进程出现异常\\n");
}
}
else
{
printf("等待子进程失败\\n");
}
sleep(2);
}
return 0;
}
运行结果如下 
waitpid等待多个子进程
//脚本代码
while :; do ps ajx | head –1 && ps ajx | grep testWait | grep –v grep; sleep 1; echo "—————————–"; done
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#define N 5
void RunChild()
{
int cnt = 2;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
int main()
{
for(int i = 0; i < N; i++)
{
pid_t id = fork();
if(id == 0)
{
RunChild();
exit(i);//区分子进程的退出码,因为这个i是在父进程循环中的,父进程的
} //代码和数据拷贝给子进程
}
for(int j = 0; j < N; j++)
{
int status = 0;
pid_t ret = waitpid(–1, &status, 0);//waitpid阻塞等待当前进程的任意子进程
if(ret > 0)
{
printf("父进程等待一个子进程成功, ");
if(WIFEXITED(status))
{
printf("子进程代码执行完了, 子进程的pid: %d, 退出码: %d\\n", ret, WEXITSTATUS(status));
}
else
{
printf("子进程出现异常了\\n");
}
}
}
sleep(2);
return 0;
}
运行结果如下 
六、非阻塞轮询

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#define TASK_NUM 3 //创建任务的个数
void RunChild()
{
int cnt = 5;
while(cnt)
{
printf("i am child process, pid: %d, ppid: %d, cnt: %d\\n", getpid(), getppid(), cnt);
cnt—;
sleep(1);
}
}
typedef void(*task_t)();//函数指针
void task1()
{
printf("这是一个执行打印日志的任务, pid: %d\\n", getpid());
}
void task2()
{
printf("这是一个执行检测网络健康状况的任务, pid: %d\\n", getpid());
}
void task3()
{
printf("这是一个执行绘制图形化界面的任务, pid: %d\\n", getpid());
}
task_t tasks[TASK_NUM];//函数指针数组(向量数组)
void InitTask()//初始化函数指针数组为NULL
{
for(int i = 0; i < TASK_NUM; i++)
{
tasks[i] = NULL;
}
}
int AddTask(task_t t)//新增任务
{
int i = 0;
for(; i < TASK_NUM; i++)//找到为空的位置
{
if(tasks[i] == NULL)
{
break;
}
}
if(i == TASK_NUM)//如果成立,那么表示此时函数指针数组满了,没有为NULL的位置,无法插入
{ //此时返回-1表示插入失败
return –1;
}
tasks[i] = t;//如果到这里说明找到了为NULL的位置,进行赋值我们要插入的函数指针即可
return 0;//返回0表示插入成功
}
void ExecuteTask()//执行函数指针数组中的所有任务
{
for(int i = 0; i < TASK_NUM; i++)//循环遍历调用函数指针即可
{
if(tasks[i])
{
tasks[i]();
}
}
}
int main()
{
//初始化函数指针数组为NULL,并且插入三个任务
InitTask();
AddTask(task1);
AddTask(task2);
AddTask(task3);
pid_t id = fork();
if(id < 0)
{
perror("fork");
return errno;
}
else if(id == 0)
{
RunChild();
exit(2);
}
else
{
//id > 0(父进程)
while(1)//循环执行非阻塞+做自己的事情
{
int status = 0;
int ret = waitpid(id, &status, WNOHANG);
if(ret < 0)//表示此时等待失败
{
perror("waitpid");
break;//一定要break退出,因为后面可能会有其它的代码要执行
}
else if(ret > 0)//等待成功
{
printf("我是父进程,我等待子进程成功了\\n");
if(WIFEXITED(status))
{
printf("子进程的代码是正常跑完的, 子进程的pid: %d, 子进程的退出码为: %d\\n", ret, WEXITSTATUS(status));
}
else
{
printf("子进程出现异常\\n");
}
break;//一定要break退出,因为后面可能会有其它的代码要执行
}
else//ret == 0, 此时执行自己的事情即可
{
ExecuteTask();//执行所有的任务
sleep(1);//休眠1秒, 否则可能出现子进程无法调度
}
}
}
return 0;
}
运行结果如下 
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
while(1)
{
printf("i am process, pid: %d\\n", getpid());
sleep(2);
}
return 0;
}
运行结果如下 
总结
以上就是今天的博客内容啦,希望对读者朋友们有帮助 水滴石穿,坚持就是胜利,读者朋友们可以点个关注 点赞收藏加关注,找到小编不迷路!




