【lesson15】进程控制之进程等待(2)

文章目录

  • 进程等待
  • 阻塞式等待
  • 非阻塞式等待
  • 非阻塞式等待 vs 阻塞式等待

进程等待

上次我们讲了许多关于进程等待的必要性和重要性还有其函数的使用方法,这次我们主要介绍函数细节方面的问题。

阻塞式等待

代码演示进程阻塞式等待
代码:

#include <stdlib.h>    
#include <sys/types.h>    int main()    
{    pid_t id = fork();    if(id == 0)    {    while(1)    {    printf("I am child id:%d\n",getpid());    sleep(1);    }    exit(2);    }    else if(id > 0)    {    printf("I am father id:%d\n",getpid());    int status = 0;    pid_t result = waitpid(id,&status,0);                                                                      if(result > 0)    {    printf("father waitpid success, exit_code:%d, exit_signal:%d\n",(status>>8)&0xFF,status&0x7F);    }    }    else    {    printf("create child process fail");    exit(1);    }    return 0;    
} 

演示:用三个窗口观察
窗口2:每个一秒监控一下进程
窗1:运行代码
窗口0:发送信号杀死子进程,查看父进程是否会等待成功

监控指令:

 while :; do ps axj | head -1 && ps axj | grep mytest | grep -v grep; sleep 1; echo "################################################################"; done

在这里插入图片描述
而这时我们杀掉子进程
在这里插入图片描述
这时我们可以看到,父进程等待工程,然后也随之退出,但是这里的等待是阻塞式等待,等待的时候父进程啥事也做不了

非阻塞式等待

那么如何非阻塞式等待呢?
在这里插入图片描述
我们会看到waitpid中有options
0:为阻塞式等待
WANOHANG:为非阻塞式等待

那么WANOHANG时什么呢?
我们知道Linux的内核是用C语言写的,而系统调用接口是Linux自己实现的并且提供的,所以这些接口全是C语言函数,所以Linux一般提供的大写标记位如:WNOHANG,其实就是宏定义。
证明:
在这里插入图片描述

非阻塞式等待 vs 阻塞式等待

阻塞式等待理解:我们应该都经历过手机或者电脑要打开某应用时突然就很卡,有时肯就卡在那了,怎么按都没有反应,在系统层面就是该进程没有被CPU调度。这时可能CPU很忙,所以这个进程要么是在阻塞对列中,要么就是在等待被调度。

非阻塞式等待理解:如果父进程通过调用waitpid来进行等待,检测到该子进程没有退出,waitpid这个系统调用立马返回。
waitpid的大概执行逻辑:
在这里插入图片描述
进程阻塞本质是阻塞在系统内部,进程阻塞时后面代码就不会再执行了。
当条件满足时父进程会被唤醒,那么是从哪里开始唤醒的?
在这里插入图片描述
所以waitpid重新调用还是从if的后面开始运行
非阻塞调用是如果子进程还没退出就直接return 0
在这里插入图片描述
阻塞一般都是在内核中阻塞,然后等待被唤醒。

讲个故事来理解阻塞等待和非阻塞等待
故事背景:华清中学的期中考要开始了,大家都在着手备考。
人物:
在这里插入图片描述
故事开始:
要期中考了,小华一个字都没学,他准备请小明吃饭,然后找小明去要课堂笔记顺便让他给自己画个重点。
于是小华就去到小明的宿舍楼下,热后打电话给小明
在这里插入图片描述
于是小华等啊等,等了几乎2个小时左右,话费都要扣光了,最后小明回复说要下来了,小华喜极而泣。
最后在小明的帮助下小华,顺利的通过了期中考。

过来几个月,华清中学的期末考来了,小明又没学习于是他又到小明宿舍楼下,准备请小明吃饭顺便找小明去要课堂笔记,也让他给自己画个重点。
在这里插入图片描述
小华又要等,但是小华想起了上次的经历,于是汲取了上次的教训。
在这里插入图片描述
之后小华就在楼下等待同时开启了游戏,每一把游戏结束,小华就打电话给小明一次,问他好了没,玩了几把游戏之后,小明终于做完了作业,这时小华也打电话给了小明,小明回复小华说好了。于是两人就一起去吃饭。

类比:
小华:用户
打电话:系统接口调用
小明:操作系统

第一次小华的电话一直截图就是:阻塞式等待
第二次小华没结束一把游戏之后打一个电话给小明就是:基于非阻塞调用的轮询检测方案。

那么为什么要学阻塞和非阻塞?
因为我们未来编写的代码内容或者网络代码大部分都是IO类别,会不断的面临阻塞和非阻塞接口!

更改代码为非阻塞等待:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/types.h>int main()
{pid_t id = fork();if(id == 0){while(1){printf("I am child id:%d\n",getpid());sleep(1);}exit(2);}else if(id > 0){/*printf("I am father id:%d\n",getpid());int status = 0;pid_t result = waitpid(id,&status,0);if(result > 0){printf("father waitpid success, exit_code:%d, exit_signal:%d\n",(status>>8)&0xFF,status&0x7F);}*/int quit = 0;                                                                                                                                                       while(!quit){int status = 0;pid_t res = waitpid(-1,&status,WNOHANG);if(res > 0){printf("等待子进程成功,退出码:%d\n",WEXITSTATUS(status));quit = 1;}else if(res == 0)                                                                                                                                                 {printf("子进程还在运行中,暂时还没有退出,父进程可以再等一下,处理一下其它事情??\n");sleep(1);}else {printf("wait 失败\n");quit = 1;}}}else {printf("create child process fail");exit(1);}return 0;
}

运行测试:
在这里插入图片描述
我们可以看到,父进程可以做自己的是,跟之前的阻塞式等待不一样了。
在这里插入图片描述
我们看到用信号杀掉了子进程,父进程也回收了子进程
那么非阻塞式等待具体用法呢?
可以用来派发任务
更改代码为可执行任务的版本:

#include <iostream>
#include <vector>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/types.h>typedef void (*handler_t) ();//函数指针
std::vector<handler_t> handlers;
void fun_one()
{printf("这是临时任务1\n");
}void fun_tow()
{printf("这是临时任务2\n");
}void load()
{handlers.push_back(fun_one);handlers.push_back(fun_tow);
}int main()
{pid_t id = fork();if(id == 0){while(1){printf("I am child id:%d\n",getpid());sleep(1);}exit(2);}                                                                                                                                                                     else if(id > 0){/*printf("I am father id:%d\n",getpid());int status = 0;pid_t result = waitpid(id,&status,0);if(result > 0){printf("father waitpid success, exit_code:%d, exit_signal:%d\n",(status>>8)&0xFF,status&0x7F);}*/int quit = 0;while(!quit){int status = 0;pid_t res = waitpid(-1,&status,WNOHANG);if(res > 0){printf("等待子进程成功,退出码:%d\n",WEXITSTATUS(status));quit = 1;}else if(res == 0){printf("子进程还在运行中,暂时还没有退出,父进程可以再等一下,处理一下其它事情??\n");if(handlers.empty()) load();for(auto iter: handlers){iter();//sleep(1);}sleep(1);}else {printf("wait 失败\n");quit = 1;}}}else {printf("create child process fail");exit(1);}return 0;
}

运行演示:
在这里插入图片描述
这样以后想让父进程闲了执行任何任务的时候,只要向load里面插入任务函数地址,就可以让父进程执行对应的任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/277448.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STL中sort的底层实现

文章目录 1、源码分析2、算法优化3、总结 在讲解STL中sort的底层原理之前&#xff0c;先引申出这样几个问题&#xff1f; ①STL中sort的底层是采用哪种或者哪几种排序&#xff1f; ②STL中sort会导致栈溢出吗&#xff1f; ③快速排序的时间复杂度是不稳定的 l o g 2 n log_2n l…

力扣22. 括号生成(java 回溯法)

Problem: 22. 括号生成 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 我们首先要知道&#xff0c;若想生成正确的括号我们需要让右括号去适配左括号&#xff0c;在此基础上我们利用回溯去解决此题目 1.题目给定n个括号&#xff0c;即当回溯决策路径长度等于 2 n 2n…

vue3 + ts 防抖指令,节流指令,复制指令

vue3 ts 自定义指令 防抖指令&#xff0c;节流指令&#xff0c;复制指令 本文使用了 element-ui , element-plus 官网 源文件 https://admin.spicyboy.cn/#/directives/debounceDirect 新建 copy.ts 文件 &#xff08;复制指令&#xff09; import type { Directive, Di…

深入分析ClassLocader工作机制

文章目录 一、ClassLoader简介1. 概念2. ClassLoader类结构分析 二、ClassLoader的双亲委派机制三、Class文件的加载流程1. 简介2. 加载字节码到内存3. 验证与解析4. 初始化Class对象 四、常见加载类错误分析1. ClassNotFoundException2. NoClassDefFoundError3. UnsatisfiledL…

系统的安全性设计

要设计一个安全的系统&#xff0c;除了要了解一些前面讲到的常用的保护手段和技术措施外&#xff0c;还要对系统中可能出现的安全问题或存在的安全隐患有充分的认识&#xff0c;这样才能对系统的安全作有针对性的设计和强化&#xff0c;即“知己知彼&#xff0c;百战百胜”。 下…

NO-IOT翻频,什么是翻频,电信为什么翻频

1.1 翻频迁移最终的目的就是减少网络的相互干扰&#xff0c;提供使用质量. 1.2 随着与日俱增的网络规模的扩大&#xff0c;网内干扰已成了影响网络的质量标准之一&#xff0c;为了保障电信上网体验&#xff0c;满足用户日益增长的网速需求,更好的服务客户&#xff0c;电信针对…

在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)

背景 在项目过程中&#xff0c;有时候你需要调用非C#编写的DLL文件&#xff0c;尤其在使用一些第三方通讯组件的时候&#xff0c;通过C#来开发应用软件时&#xff0c;就需要利用DllImport特性进行方法调用。本篇文章将引导你快速理解这个调用的过程。 步骤 1. 创建一个CSharp…

JMeter下载与安装

文章目录 前言一、安装java环境&#xff08;JDK下载与安装&#xff09;二、JMeter下载三、JMeter安装1.解压缩2.配置环境变量 四、JMeter启动&#xff08;启动成功则代表JMeter安装成功&#xff09;五、JMeter汉化&#xff08;将JMeter修改成中文&#xff09;1.方法一&#xff…

HTTP 301错误:永久重定向,大勇的冒险之旅

大家好&#xff0c;我是大勇&#xff0c;一个喜欢冒险的程序员。今天&#xff0c;我要和大家分享一个我在互联网世界中的冒险故事——如何处理HTTP 301错误&#xff1a;永久重定向。 那天&#xff0c;我像往常一样&#xff0c;打开我的代码编辑器&#xff0c;准备开始一天的工…

Python学习开发mock接口

#1.测试为什么要开发接口&#xff1f; 1)在别的接口没有开发好的时候, mock接口(模拟接口) 2)查看数据, 避免直接操作数据库 #2.开发接口的顺序 1)安装flask flask是一个轻量级开发框架 pip install flask 2)开发一个接口 开发步骤&#xff1a; 1.实例化一个服务server:f…

状态的一致性和FlinkSQL

状态一致性 一致性其实就是结果的正确性。精确一次是指数据有可能被处理多次&#xff0c;但是结果只有一个。 三个级别&#xff1a; 最多一次&#xff1a;1次或0次&#xff0c;有可能丢数据至少一次&#xff1a;1次或n次&#xff0c;出错可能会重试 输入端只要可以做到数据重…

黑马点评04集群下的并发安全

实战篇-08.优惠券秒杀-集群下的线程并发安全问题_哔哩哔哩_bilibili 为了应对高并发&#xff0c;需要把项目部署到多个机器构成集群&#xff0c;所以需要配置nginx。 1.如何模拟集群 通过idea的ctrl d修改配置&#xff0c;实现多个tomcat运行模拟集群 然后在nginx上配置节点&…