说在前面

今天给大家带来操作系统中进程等待的概念,我们学习的操作系统是Linux操作系统。

我们今天主要的目标就是认识wait和waitpid这两个系统调用。

前言

那么这里博主先安利一下一些干货满满的专栏啦!

手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014.3001.5482这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
算法专栏https://blog.csdn.net/yu_cblog/category_11464817.html这里是STL源码剖析专栏,这个专栏将会持续更新STL各种容器的模拟实现。

STL源码剖析https://blog.csdn.net/yu_cblog/category_11983210.html?spm=1001.2014.3001.5482


什么是进程等待

简单来说, 进程等待是进程的一种状态, 是父进程等待子进程退出时的一个过程。

当然这样描述,大家肯定是不明白的,继续向后看,我相信大家就能明白了!

为什么需要进程等待

首先,我们知道,创建一个子进程,肯定是想让子进程去完成一些不同于父进程的东西。那么当子进程执行完之后,如果父进程还没有退出,子进程的状态叫做僵尸

  • 子进程退出,父进程不管子进程,子进程就要处于僵尸状态 --- 导致内存泄漏
  • 父进程创建了子进程,是要让子进程办事儿的,那么子 进程把任务完成的怎么样?父进程需要关心吗?如果需 要,如何得知?如果不需要,该怎么处理?

当子进程结束时,子进程的结束方式有三种:

  1. 子进程代码执行完,结果正确
  2. 子进程代码执行完,结果不正确
  3. 子进程代码没有执行完,程序崩溃

那么,父进程如果要通过判断子进程的执行情况,分别进行不同操作的时候,我们的父进程就要了解子进程的执行,是属于上面三种的哪一种。与此同时,父进程还需要回收子进程。

如何进行进程等待

进程等待有两个系统调用接口:

  1. wait
  2. 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的更多相关文章

  1. Linux下同步模式、异步模式、阻塞调用、非阻塞调用总结

    转自:http://www.360doc.com/content/13/0117/12/5073814_260691714.shtml 同步和异步:与消息的通知机制有关. 本质区别 现实例子 同步模式 ...

  2. 基于mykernel完成时间片轮询多道进程的简单内核

    基于mykernel完成时间片轮询多道进程的简单内核 原创作品转载请注明出处+中科大孟宁老师的linux操作系统分析:https://github.com/mengning/linuxkernel/ ...

  3. 支持阻塞操作和轮询操作的globalfifo设备驱动代码分析以及测试代码

    #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include ...

  4. 精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方法详解

    本文是精讲响应式WebClient第2篇,前篇的blog访问地址如下: 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法 在上一篇文章为大家介绍了响应式IO模型和WebClient的基本 ...

  5. 2017年5月12日15:10:46 rabbitmq不支持非阻塞调用服务器

    就像昨天碰到的问题描述一样,问题不是出在消费者上而是在生产者发送消息出现没有得到返回值时消息通道被挂起,rabbitmq发送的消息是阻塞调用即当发生阻塞时,继续发送的消息都堆在后面.在网上看到有两个方 ...

  6. php fsockopen()方法,简化,异步非阻塞调用

    介绍在项目中遇到一个问题,就是php是同步的读取下来的,如果一个方法请求的时间长了一点, 那么整个程序走下去将会遇到阻塞,现在我想触发这个方法,但是又不影响我下下面的程序正常的走下去.查了一上午的方法 ...

  7. rabbiitmq非阻塞调用

    https://blog.csdn.net/panxianzhan/article/details/50755409 https://blog.csdn.net/u013946356/article/ ...

  8. python_非阻塞套接字及I/O流

    http://www.cnblogs.com/lixy-88428977/p/9638949.html 首先,我们要明确2个问题: 普通套接字实现的服务端有什么缺陷吗? 有,一次只能服务一个客户端! ...

  9. 网络IO-阻塞、非阻塞、IO复用、异步

    网络socket输入操作分为两个阶段:等待网络数据到达和将到达内核的数据复制到应用进程缓冲区.对这两个阶段不同的处理方式将网络IO分为不同的模型:IO阻塞模型.非阻塞模型.多路复用和异步IO. 一 阻 ...

  10. 非阻塞IO与异步IO

    一.非阻塞IO的轮询读写 ---如果当前进程有多个输入终端和多个输出终端呢?while((n=read(STDIN_FILENO,buf,buf_size))>0){    if(write(S ...

随机推荐

  1. kafka集群三、增加密码验证

    系列导航 一.kafka搭建-单机版 二.kafka搭建-集群搭建 三.kafka集群增加密码验证 四.kafka集群权限增加ACL 五.kafka集群__consumer_offsets副本数修改 ...

  2. vue结合element-ui实现多层复选框checkbox

    1.需求如上图所以: html相关代码如下: 1 <div class="intent-course-wrapper"> 2 <div class="c ...

  3. Vue源码编译过程

    Vue源码编译过程一.挂载初始化$mounted会挂载组件,不存在 render 函数时需要编译(compile);二.compile1.compile 分为 parse,optimize 和 gen ...

  4. P4837

    日了啊,这道题每个输入中有多组输入,每处理完一组输入需要清空STL的stack类对象的啊.要是自己写的栈或许能想起来重新top=1,但是这用的STL现成的stack,就忘了while(!sk.empt ...

  5. java进阶(13)--int、String、Integer互相转换

    一.转换流程图  

  6. Dubbo入门2:Springboot+Dubbo2.6.0+ZooKeeper3.4.8整合

    整合Springboot+Dubbo2.6.0+ZooKeeper3.4.8 本文主要目的:记录整合以上3个框架的配置文件的写法 此文只在<Dubbo入门1>的基础上略作修改,仅记录修改的 ...

  7. 网络要素服务(WFS)详解

    目录 1. 概述 2. GetCapabilities 3. DescribeFeatureType 4. GetFeature 4.1 Get访问方式 4.2 Post访问方式 5. Transac ...

  8. 通过宿主机查看K8S或者是容器内的Java程序的简单方法

    通过宿主机查看K8S或者是容器内的Java程序的简单方法 背景 最近一个项目的环境出现了 cannot create native process 的错误提示 出现这个错误提示时, docker ex ...

  9. [转帖]PostgreSQL中的schema和user

    https://www.cnblogs.com/abclife/p/13905336.html postgresql中,用户创建的所有对象都被创建在指定的schema(或namespace)中.其他用 ...

  10. [转帖]国产数据库到底行不行?人大金仓KINGBASE数据库与主流开源数据库性能实测

    近年来,人大金仓的数据库产品受到了外界诸多的关注.做产品,免不了要接受用户的对比和选择,数据库因其行业的自身特点,还有很多开源的技术产品同台比拼,用户因此也会产生诸多疑问,国产数据库相比开源数据库到底 ...