多进程|基于非阻塞调用的轮询检测方案|进程等待|重新理解挂起|Linux OS
说在前面
今天给大家带来操作系统中进程等待的概念,我们学习的操作系统是Linux操作系统。
我们今天主要的目标就是认识wait和waitpid这两个系统调用。
前言
那么这里博主先安利一下一些干货满满的专栏啦!
这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014.3001.5482
这里是STL源码剖析专栏,这个专栏将会持续更新STL各种容器的模拟实现。算法专栏https://blog.csdn.net/yu_cblog/category_11464817.html
STL源码剖析https://blog.csdn.net/yu_cblog/category_11983210.html?spm=1001.2014.3001.5482
什么是进程等待
简单来说, 进程等待是进程的一种状态, 是父进程等待子进程退出时的一个过程。
当然这样描述,大家肯定是不明白的,继续向后看,我相信大家就能明白了!
为什么需要进程等待
首先,我们知道,创建一个子进程,肯定是想让子进程去完成一些不同于父进程的东西。那么当子进程执行完之后,如果父进程还没有退出,子进程的状态叫做僵尸。
- 子进程退出,父进程不管子进程,子进程就要处于僵尸状态 --- 导致内存泄漏
- 父进程创建了子进程,是要让子进程办事儿的,那么子 进程把任务完成的怎么样?父进程需要关心吗?如果需 要,如何得知?如果不需要,该怎么处理?
当子进程结束时,子进程的结束方式有三种:
- 子进程代码执行完,结果正确
- 子进程代码执行完,结果不正确
- 子进程代码没有执行完,程序崩溃
那么,父进程如果要通过判断子进程的执行情况,分别进行不同操作的时候,我们的父进程就要了解子进程的执行,是属于上面三种的哪一种。与此同时,父进程还需要回收子进程。
如何进行进程等待
进程等待有两个系统调用接口:
- wait
- waitpid
wait
首先,我们先把Makefile,myproc.c准备好
然后,我们在myproc.c里面先构建一个僵尸状态,然后我们再通过进程等待的系统调用接口去解决。
如图所示:通过代码构建一个僵尸状态。
在这份代码中,5秒之后,子进程就正常退出,此时的子进程就是一个Z状态。
关于wait函数的更详细信息,我们可以通过手册来获取。
wait接口的用法
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
//返回值: 成功返回被等待进程pid,失败返回-1。
//参数: 输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
验证代码和现象如下:
waitpid
第一个参数,表示要等待的进程的子进程的pid。
刚开始我们学习代码的时候,一般只有一个父进程一个子进程的情况。但是继续往后学习,我们接触到多进程的时候,我们就要使用waitpid接口,进行执行的进程的等待。
第二个参数是一个输出型参数,我们传入一个int类型变量status的地址,waitpid会给把等待到的进程的执行情况存储到status中带回来
第三个参数表示进行选择阻塞等待方式/非阻塞等待方式(后面我们会详细讲解和区分)。
此时我们可以先看一个简单的例子:
这里我们举例子使用了阻塞式等待,即第三个参数是0。
在代码中,我们让子进程传回一个特殊的数字,表示它的进程退出码,这里我们传的是105
最后打印一下status(代码没有体现,但是现象中是加上了打印status的,很简单,加一句话就行)
我们发现status并不是传回来的105。
这是因为:status并不是按照整数的方式来使用的,它是按照比特位的方式对status进行划分,一个32个,我们只学习低16个比特位置的划分。
首先,我们所要明确的一个概念:
进程的退出码只有在进程正常结束的时候才有意义!
假设return 0表示正常退出,return 1表示段错误,exit()也一样,返回退出码的前提是,程序正常执行到了这一句。如果程序异常退出了,退出码毫无意义。
那么如何判断程序是否异常退出呢?看所接受到的信号是否为0
如果所接受到的信号为0 -- 表示程序正常退出。
接下来就是一个C语言的问题了 -- 我们如何从status这个32位整数里面得到退出码和信号呢?
这里博主直接给出结果了,如果不明白的伙伴要补习一下C语言了。
- 退出码:(status>>8) & 0xFF
- 信号:status & 0x7F
此时,博主再给大家再次强调一下这个重要概念
两个重点:
- 程序异常退出,本质是进程异常退出,本质是OS杀掉了这个进程
- OS怎么杀——发送信号
一些程序异常退出的例子
讲到这里,我们再回答三个问题:
1. 父进程通过wait/waitpid可以拿到子进程的退出结果,为什么要用waitpid/wait函数呢??直接全局变量不行吗??
当然不行,进程具有独立性,那么数据就要进行写 时拷贝,父进程肯定是拿不到的,更不用说信号了。
2. 既然进程是具有独立性的,进程退出码,不也是子进程的数据吗??父 进程又凭什么拿到呢?? wait/waitpid究竟干了什么呢?
这里我们要从僵尸进程说起
僵尸进程:至少要保留 pcb信息!task_struct里面保留了进程退出时的退 出结果信息!!
因此,wait/waitpid本质是读取了子进程的task_struct结构!
3. 那么现在的问题是:wait/waitpid有这个权利吗???
别忘了, task_stuct是内核数据结构对象!当然有这个权利啊! 因为它们是系统调用啊! 它们在干活儿不就是OS在干活儿吗?
一个小总结
waitpid/wait 可以在目前的情况下,让进 程退出具有一定的顺序性! 将来可以让父进程进行更多的收尾工作!
一些补充
对于上层使用的人来说,我使用的时候还要对操作系统内核有一定了解,还得知道status的构成,我才能提取信息这样未免太麻烦了!
其实操作系统是给我们提供了宏的,一开始博主不告诉大家,是希望大家理解status的低层构成。
阻塞等待和非阻塞等待
因此,如果我们调用的是阻塞等待,父进程在子进程尚未结束的时候的状态是,挂起!
重新理解挂起
这种阻塞等待,其实是在系统调用接口(wait系列函数)中阻塞 也就是内核中阻塞
比如以前我们的scanf,cin 如果我们一直不往键盘输入。此时OS发现缓冲区里面资源没有就绪 系统就把我们的进程挂起! 此时,表面上看,就是卡住了!
而在哪里卡住? 由冯诺依曼体系我们知道, 键盘这些输入硬件,到显示器这种输出硬件中,肯定会经过操作系统,所以其实本质上也是在内核中卡住了! scanf,cin必定封装了系统调用!
阻塞的本质,是在内核中阻塞,在内核中把进程挂起!
基于非阻塞调用的轮询检测方案
那么非阻塞调用的时候,直接就返回了,父进程不等。
那我们怎么知道子进程的状态呢? 我们会每隔一段时间去检测一下子进程的状态,如果监测到子进程结束,就释放子进程这个叫做 --- 基于非阻塞调用的轮询检测方案。
总结
相信看到这里,大家对Linux操作系统中的进程等待已经有了一定的了解了。操作系统的学习是必要的,虽然它可能很枯燥。如果大家觉得这篇文章有帮助的话,不要忘记一键三连哦!!
多进程|基于非阻塞调用的轮询检测方案|进程等待|重新理解挂起|Linux OS的更多相关文章
- Linux下同步模式、异步模式、阻塞调用、非阻塞调用总结
转自:http://www.360doc.com/content/13/0117/12/5073814_260691714.shtml 同步和异步:与消息的通知机制有关. 本质区别 现实例子 同步模式 ...
- 基于mykernel完成时间片轮询多道进程的简单内核
基于mykernel完成时间片轮询多道进程的简单内核 原创作品转载请注明出处+中科大孟宁老师的linux操作系统分析:https://github.com/mengning/linuxkernel/ ...
- 支持阻塞操作和轮询操作的globalfifo设备驱动代码分析以及测试代码
#include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include ...
- 精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方法详解
本文是精讲响应式WebClient第2篇,前篇的blog访问地址如下: 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法 在上一篇文章为大家介绍了响应式IO模型和WebClient的基本 ...
- 2017年5月12日15:10:46 rabbitmq不支持非阻塞调用服务器
就像昨天碰到的问题描述一样,问题不是出在消费者上而是在生产者发送消息出现没有得到返回值时消息通道被挂起,rabbitmq发送的消息是阻塞调用即当发生阻塞时,继续发送的消息都堆在后面.在网上看到有两个方 ...
- php fsockopen()方法,简化,异步非阻塞调用
介绍在项目中遇到一个问题,就是php是同步的读取下来的,如果一个方法请求的时间长了一点, 那么整个程序走下去将会遇到阻塞,现在我想触发这个方法,但是又不影响我下下面的程序正常的走下去.查了一上午的方法 ...
- rabbiitmq非阻塞调用
https://blog.csdn.net/panxianzhan/article/details/50755409 https://blog.csdn.net/u013946356/article/ ...
- python_非阻塞套接字及I/O流
http://www.cnblogs.com/lixy-88428977/p/9638949.html 首先,我们要明确2个问题: 普通套接字实现的服务端有什么缺陷吗? 有,一次只能服务一个客户端! ...
- 网络IO-阻塞、非阻塞、IO复用、异步
网络socket输入操作分为两个阶段:等待网络数据到达和将到达内核的数据复制到应用进程缓冲区.对这两个阶段不同的处理方式将网络IO分为不同的模型:IO阻塞模型.非阻塞模型.多路复用和异步IO. 一 阻 ...
- 非阻塞IO与异步IO
一.非阻塞IO的轮询读写 ---如果当前进程有多个输入终端和多个输出终端呢?while((n=read(STDIN_FILENO,buf,buf_size))>0){ if(write(S ...
随机推荐
- 使用屏幕捕捉API:一站式解决屏幕录制需求
随着科技的发展,屏幕捕捉API技术逐渐成为一种热门的录屏方法.本文将详细介绍屏幕捕捉API技术的原理.应用场景以及如何利用这一技术为用户提供便捷.高效的录屏体验. 在线录屏 | 一个覆盖广泛主题工具的 ...
- GDP折线图
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset=" ...
- apache mina
本文为博主原创,未经允许不得转载: Apache Mina(Apache Multipurpose Infrastructure for Network Applications)是一个基于Java的 ...
- 基于python+django的家教预约网站-家教信息管理系统设计与实现
该系统是基于python+django开发的家教预约网站.是给师妹做的课程作业.大家在学习过程中,遇到问题可以在github给作者留言. 效果演示 前台地址: http://jiajiao.gitap ...
- 远程复制文件-scp
- Jrebel与Xrebel教学
简介 JRebel和XRebel是两个非常有用的工具,可以显著提升Java开发人员的生产力和应用程序性能. JRebel是一个强大的Java开发工具,它允许开发人员在不重新启动应用程序的情况下进行代码 ...
- cancal报错 config dir not found
替换classpath中间封号两边的值
- [转帖]聊聊TPS、QPS、CPS概念和区别
https://cloud.tencent.com/developer/article/1859053 TPS 概念 TPS:是TransactionsPerSecond的缩写,也就是事务数/秒.它是 ...
- [转帖]JVM中年轻代里的对象什么情况下进入老年代?以及老年代垃圾回收算法-标记整理算法
1.躲过15次GC之后进入老年代 系统刚启动时,创建的各种各样的对象,都是分配在年轻代里. 随着慢慢系统跑着跑着,年轻代满了,就会出发Minor GC ,可能1%的少量存活对像转移到空着的Surviv ...
- [转帖]nginx 剖析 request_time和upstream_response_time的误区、区别
https://cloud.tencent.com/developer/article/1767981 首先,澄清一个误区 upstream_response_time必须在upstream配置时才能 ...