Linux操作系统学习之---进程状态

       

目录

        明确进程的概念:

       

Linux下的进程状态:

        虚拟终端的概念:

         见一见现象:

        用途之一 : 结合指令来监控进程的状态:

和进程强相关的系统调用函数接口:

        getpid()和getppid():

        fork():

        fork函数创建子进程的分流逻辑: 

        进程之间具有独立性: 

         进程中存在的写时拷贝:

见一见进程状态:       

  在代码层面见一见R和S两种状态:

        系统调用函数 getpid() 和 getppid()

        代码和实操: 

         出现的疑点:

在代码层面见一见 Z状态:

        概念理解:

         代码实践:

粗略了解一下D状态:

补充说明X和T状态:

在文件层面见一见进程:

特殊的进程:孤儿进程

        验证代码: 

        见一见效果: 

         最终的去处:


在笼统的认识了整个操作系统之后,就可以挑一个局部开始学习. 进程就是一个很好的选择 , 他就想一个不知疲倦的员工,等待着使用者发号施令 . 我们的每一个操作,最终能够起到作用都是以来着一个个进程 , 所以他也是离我们最近的元素 . 

        明确进程的概念:

        一切程序最开始都是乖乖待在磁盘里的一堆二进制文件 , 当打开电脑后 , 不管是系统内置的程序 , 还是我们自己的程序 , 加载到内存 , 就变成了进程

        具体来讲 , 当加载一个程序时 , 原本在磁盘里的代码和数据被加载到内存 , 经过操作系统的无形大手 , 将这一堆内容定义成了统一的格式---结构体(操作系统底层通常都是c语言) .

        因此 , 真正称得上进程并非单纯的"程序"这一抽象概念 , 而是进程控制块PCB(结构体实例化处的对象 Process Control BLOCK) + 代码和数据 .

        我们管理一个进程 , 本质上就是对操作系统发号施令,让他来管理这两个内容.

       

Linux下的进程状态:

运行(R)指的是处于调度队列里的进程
可中断睡眠(S)又称作阻塞,通常是在等待各种事件时的状态
不可中断睡眠(D)

通常是在等待IO操作时的状态

停止(T)比如我们按下Ctrl+z , 一个前台进程就停止了
死亡(X)这个状态一般我们看不到

        虚拟终端的概念:

         由于咱通常都是用windows电脑来学习Linux操作系统,所以配置虚拟机啥的比较麻烦 , 索性就用xshell之类的外壳程序来连接云服务器进行操作 . 

        而一台云服务器可以同时供多个用户使用 , 甚至 , 同一个用户还可以同时打开两个终端同时对一台机器进行操作 , 看着是不是有些让人匪夷所思 ,下面简单解释一下子:

         见一见现象:

 现象:

 只打开一个终端时:

用同一个用户多开一个终端时: 

        用途之一 : 结合指令来监控进程的状态:

        比方说我们初次学习进程,了解了一堆概念 , 那么久可以开一个终端窗口用于运行我们的程序 , 开第二个窗口用于监控我的的程序状态(程序运行起来后就是一个进程)

和进程强相关的系统调用函数接口:

        getpid()和getppid():

        这俩哥们很简单 , getpid()函数返回当前进程的pid ;  getppid()返回父进程的pid

        fork():

        这个函数相较于c语言的大部分函数来说都很神奇 , 调用它就会为当前进程创建一个子进程 , 而我们知道子进程创建出来是为父进程分担任务的 , 这就涉及到它的三个返回值了

        fork函数创建子进程的分流逻辑: 

        fork有三个返回值:

  1.  如果是父进程 , 返回整数
  2. 如果是子进程 , 返回0
  3. 如果创建子进程失败 , 返回负数

        因此虽然父子进程拥有一样的代码 , 但fork的返回值不会骗人 , 只要我们自己在代码里对fork()的返回值进行判断 , 根据返回值的不同执行不同的代码 , 就可以达到代码分流的目的了

        简单来说

        进程之间具有独立性: 

        上图中的父子进程似乎执行的是同一段代码 , 只是不同的部分 , 其实父进程和子进程是完全独立的 , 他们具有不同的pid.

        之所以可以执行同一块代码 , 只是因为代码本身在程序运行期间是只读的 , 存放在代码区, 不属于任何进程自己的的内容 , 因此父子进程都可以访问同一段代码(保存同样的指针)

         进程中存在的写时拷贝:

       尽管进程之前是独立的,但是在刚刚创建子进程时 , 为了提升效率 , 子进程新创建的PCB的内容几乎是从父进程那完完全全拷贝而来的(除了pid等等比较特殊的属性才会不同).

        当调用fork函数时,会创建一个当前进程的子进程 , 子进程会拥有和当前进程同样的代码和数据.

        代码是存在于代码区带只读内容 , 父、子进程只需要保存相同的指针变量指向对应的代码即可

        而数据不同 ,尤其是变量 ,可能需要被频繁的修改 ,为了避免多个进程各自修改同一个变量对其他进程造成影响 , 就有了写时拷贝的设计

        一旦涉及数据的修改 , 操作系统就会为修改数据的进程新开辟一块空间 , 拷贝一份原来的数据让他进行自己的操作 . 

        这就像"借鉴"同学的作业一样 , 你只是看看还好 , 如果你想要修改 , 哪怕只是改一下名字 , 也得你自己另外弄一份来改!!!

见一见进程状态:       

  在代码层面见一见R和S两种状态:

        系统调用函数 getpid() 和 getppid()

    定义在<unistd.h>头文件中 , getpid会返回当前进程(运行的程序)的进程pid , pid是一个进程的唯一标识符, 类似于一个学生的学号 .

    getppid()则会返回当前进程(运行的程序)的父进程的pid , 当前的进程称为子进程 , 由父进程来创建这个进程. 就好像上级领导吩咐了一个下属来帮自己干活.

        接下来写一个死循环程序 , 其中使用了一个死循环来不停的调用getpid()和getppid()来打印子进程和父进程的pid( )

        接着打开第二个窗口来监视他的状态

        用于监视的指令 : while true; do ps -ajx | head - | ps -ajx | grep code; sleep 1; done

        其中code是我将要执行的程序

        代码和实操: 

#include<unistd.h> //类unix操作系统相关函数的头文件,此处用于getpid()和getppid()while(1){printf("我是一个进程,我的pid:%d , 我的ppid:%d\n",getpid(),getppid());sleep(1);}

         出现的疑点:

  1.        在刚才的程序里 , 明明是好像一直在一秒一秒的打印内容 , 为啥进程的状态是S+ 呢? 其实和S状态的定义和sleep函数有关:
  2.         S状态称为可中断睡眠状态 , 通常发生在进程等待某种指令的间隙 
  3.         我的程序里有sleep函数 , 是的每次执行完一次printf后就会等待一秒
  4.         可是printf进行打印的操作相较于sleep的1秒来说实在是太短了,以至于ps指令几乎没法捕捉到进程进行输出时的状态(R+)
  5.         如果想要看到程序为运行状态 , 只需要去掉sleep ,让进程频繁的进行打印.

         当去掉了代码和监控指令里的sleep后,总算是可以观察到R+状态了哈哈哈哈哈.

在代码层面见一见 Z状态:

        概念理解:

        Z(zombie)状态叫做僵尸状态 , 十分形象 :

        想象一个人突然倒在路边 , 没有了呼吸 , 可以当叫来警察和救护车后 , 并不会直接把人抬走然后通知家属 , 而是让医生先检测和抢救一下 , 如果没有这个过程 , 贸然带走尸体甚至是违法的 . 

        医生进行检测和抢救的过程 , 就是父进程回收子进程退出(死亡)信息的过程 , 如果没有回收 , 谁也不敢贸然处理(即不能释放这个进程的PCB) , 因此尸体在躺在地上的时候就会污染环境和占据空间(即迟迟不释放的PCB会占用内存空间).

        结论 : 当一个进程的使命结束 , 就会变成僵尸状态 , 如果没有父进程来获取他的退出信息 , 这个僵尸进程就会一直占用内存空间 ,造成空间浪费.

         代码实践:

        下面的代码让父进程一直运行 , 而子进程执行一条printf函数后就结束:

int ret = fork();if(ret > 0)//父进程{while(1){printf("我是父进程,pid:%d,我在😪\n",getpid());sleep(1);}}else if(ret == 0)//子进程{printf("我是子进程,pid:%d,我很快就要挂了....💀\n",getpid());}else  //创建子进程失败{//失败的情况很少见}

         下面是运行的内容和进程的监控内容 

粗略了解一下D状态:

定义 : 不可中断休眠 , 通常回出现在一个进程等待IO操作时 , 可以在一定程度上避免数据丢失

          这个很难验证 , 但可以文字叙述一下(情况之一):

  •         系统的内存资源是有限的 , 因此操作系统会在系统资源告急时采取一些策略 , 将不那么重要的进程的大部分内容给暂时移走
  •         当系统的资源告急时很严重了 , 为了表面上给用户一个良好的使用体验 , 除了看得见的前台进程 , 其他的不分青红皂白就会给杀掉!!!
  •         可是有的进程可能正在对磁盘里面写入数据 , 接着等待磁盘的处理结果 , 这时如果进程被杀掉了 , 不管写入数据是否成功 , 磁盘的处理结果可能就会丢失 , 用户层面对此是全然不知的!!!
  •         因此对于进行IO操作的进程 , 比如开个后门 , 让它们可以平平安安的获取操作的结果 , 也就有了D状态 , 故而也叫磁盘休眠状态

补充说明X和T状态:

        X状态 : 一个死透了的进程 , 通常上层用户看不见 , 毕竟后事处理完后就没有为他留着内存空间的必要了 . (上面提到过的僵尸进程就是还没死透但还需要被处理的进程)

         T状态:一个暂停了的进程 , 比如当使用Ctrl +z时就会导致进程停止 , 如果放着不管就会一直占用空间 , 造成资源浪费!!!

在文件层面见一见进程:

        Linux的一大设计理念---一切皆文件 . 连时而创建,时而销毁的进程也不例外

 系统根目录下的一个proc目录存放了和进程相关的文件:

如果随便查看一个管理进程的目录文件的内容 , 结果如下 :

当然喽,如果是查看自己的进程的路径(比如自己运行的c语言程序) , 情况会变化

特殊的进程:孤儿进程

        在验证僵尸进程时 , 情况是子进程先于父进程结束 , 而如果是父进程先结束后留下孤零零的子进程会怎么样呢? 答案是孤儿进程,名字也很形象啦.

        验证代码: 

//父进程立马结束,子进程死循环一直干活
int ret = fork();if(ret > 0)//父进程{printf("我是父进程,pid:%d,我马上溜啦🏃‍♂️💨\n",getpid());}else if(ret == 0)//子进程{while(1){printf("我是子进程,pid:%d,我在等我爸开路虎来接我😎\n",getpid());sleep(1);}}else  //创建子进程失败{//失败的情况很少见}

        见一见效果: 

        当运行程序 , 我们可以看到子进程的父进程的pid马上变成了1 , 并且 , 无法用Ctrl+c来杀掉这个进程!!!如下图: 

         pid为1的进程是最重要的系统进程(Linux下叫做init) , 甚至可以把他就当做操作系统本身 .(其实还有pid为0的进程,只不过在创建1号进程后很快就结束了)

        当父进程先于子进程退出 , 那后续子进程结束后就没有进程可以获取他的退出信息 , 从而就永远无法被销毁 , 这时就会由pid为1的系统进程来收养他 , 因此父进程提前退出的子进程也叫做孤儿进程

         最终的去处:

        孤儿进程被pid为1的init系统进程收养后 , 还会变成后台进程 , 无法被ctrl+c(针对前台进程)给终止 , 但可以使用 kill -9 pid来杀掉 .否则 , 系统不停止运行 , 这个子进程就会一直占用内存资源

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

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

相关文章

何小鹏在得意的笑

"小鹏汽车率先迈出了造车新势力出海一大步" 作者 | 魏强 编辑 | 卢旭成 4月15日&#xff0c;小鹏汽车在香港举行小鹏全球热爱之夜和2025首款全球旗舰小鹏X9上市发布会。 当小鹏汽车创始人何小鹏把香车X9交付给香港首批车主的时候&#xff0c;脸上露出经典的笑脸。…

@Autowird 注解与存在多个相同类型对象的解方案

现有一个 Student 类&#xff0c;里面有两个属性&#xff0c;分别为 name 和 id&#xff1b;有一个 StuService 类&#xff0c;里面有两个方法&#xff0c;返回值均为类型为 Student 的对象&#xff1b;还有一个 StuController 类&#xff0c;里面有一个 Student 类型的属性&am…

黑马商城项目(三)微服务

一、单体架构 测试高并发软件 二、微服务 三、SpringCloud 四、微服务拆分 黑马商城模块&#xff1a; 服务拆分原则&#xff1a; 拆分服务&#xff1a; 独立project&#xff1a; maven聚合&#xff1a; 拆分案例&#xff1a; 远程调用&#xff1a; package com.hmall.cart.…

PyTorch:学习 CIFAR-10 分类

&#x1f50d; 开始你的图像分类之旅&#xff1a;一步一步学习 CIFAR-10 分类 图像分类是计算机视觉中最基础的任务之一&#xff0c;如果你是初学者&#xff0c;那么以 CIFAR-10 为训练场是一个不错的选择。本文一步一步带你从零开始&#xff0c;学习如何用深度学习模型实现图…

3.学习笔记--Spring-AOP总结(p39)-Spring事务简介(P40)-Spring事务角色(P41)-Spring事务属性(P42)

1.AOP总结&#xff1a;面向切面编程&#xff0c;在不惊动原始基础上为方法进行功能增强。 2.AOP核心概念&#xff1a; &#xff08;1&#xff09;代理&#xff1a;SpringAOP的核心是采用代理模式 &#xff08;2&#xff09;连接点&#xff1a;在SpringAOP中&#xff0c;理解为任…

数据库-day06

一、实验名称和性质 分类查询 验证 综合 设计 二、实验目的 1&#xff0e;掌握数据查询的Group by &#xff1b; 2&#xff0e; 掌握聚集函数的使用方法。 三、实验的软硬件环境要求 硬件环境要求&#xff1a; PC机(单机) 使用的软件名称、版本号以及模块&#xff1a; …

看门狗定时器(WDT)超时

一、问题 Arduino 程序使用<Ticker.h>包时&#xff0c;使用不当情况下&#xff0c;会导致“看门狗WDT超时” 1.1问题控制台报错 在串口监视器显示 --------------- CUT HERE FOR EXCEPTION DECODER ---------------Soft WDT resetException (4): epc10x402077cb epc2…

AI在多Agent协同领域的核心概念、技术方法、应用场景及挑战 的详细解析

以下是 AI在多Agent协同领域的核心概念、技术方法、应用场景及挑战 的详细解析&#xff1a; 1. 多Agent协同的定义与核心目标 多Agent系统&#xff08;MAS, Multi-Agent System&#xff09;&#xff1a; 由多个独立或协作的智能体&#xff08;Agent&#xff09;组成&#xff…

Wireshark TS | 异常 ACK 数据包处理

问题背景 来自于学习群里群友讨论的一个数据包跟踪文件&#xff0c;在其中涉及到两处数据包异常现象&#xff0c;而产生这些现象的实际原因是数据包乱序。由于这两处数据包异常&#xff0c;都有点特别&#xff0c;本篇也就其中一个异常现象单独展开说明。 问题信息 数据包跟…

【React】项目的搭建

create-react-app 搭建vite 搭建相关下载 在Vue中搭建项目的步骤&#xff1a;1.首先安装脚手架的环境&#xff0c;2.通过脚手架的指令创建项目 在React中有两种方式去搭建项目&#xff1a;1.和Vue一样&#xff0c;先安装脚手架然后通过脚手架指令搭建&#xff1b;2.npx create-…

深入浅出 NVIDIA CUDA 架构与并行计算技术

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《深度探秘&#xff1a;AI界的007》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、CUDA为何重要&#xff1a;并行计算的时代 2、NVIDIA在…

pytorch学习02

自动微分 自动微分模块torch.autograd负责自动计算张量操作的梯度&#xff0c;具有自动求导功能。自动微分模块是构成神经网络训练的必要模块&#xff0c;可以实现网络权重参数的更新&#xff0c;使得反向传播算法的实现变得简单而高效。 1. 基础概念 张量 Torch中一切皆为张…

Java虚拟机(JVM)平台无关?相关?

计算机的概念模型 计算机实际上就是实现了一个图灵机模型。即&#xff0c;输入参数&#xff0c;根据程序计算&#xff0c;输出结果。图灵机模型如图。 Tape是输入数据&#xff0c;Program是针对这些数据进行计算的程序&#xff0c;中间横着的方块表示的是机器的状态。 目前使…

satoken的奇奇怪怪的错误

发了 /user/getBrowseDetail和/user/getResponDetail&#xff0c;但为什么进入handle里面有三次&#xff1f;且第一次的handle类型是AbstractHandleMapping$PreFlightHttpRequestHandlerxxx,这一次进来的时候flag为false&#xff0c;StpUtils.checkLogin抛出了异常 第二次进来的…

【KWDB 创作者计划】_上位机知识篇---SDK

文章目录 前言一、SDK的核心组成API(应用程序接口)库文件(Libraries)开发工具文档与示例依赖项与环境配置二、SDK的作用简化开发流程确保兼容性与稳定性加速产品迭代功能扩展与定制三、SDK的典型应用场景硬件设备开发操作系统与平台云服务与API集成游戏与图形开发四、SDK与…

golang处理时间的包time一次性全面了解

本文旨在对官方time包有个全面学习了解。不钻抠细节&#xff0c;但又有全面了解&#xff0c;重点介绍常用的内容&#xff0c;一些低频的可能这辈子可能都用不上。主打一个花最少时间办最大事。 Duration对象: 两个time实例经过的时间,以长度为int64的纳秒来计数。 常见的durati…

PyCharm Flask 使用 Tailwind CSS 配置

使用 Tailwind CSS 步骤 1&#xff1a;初始化项目 在 PyCharm 终端运行&#xff1a;npm init -y安装 Tailwind CSS&#xff1a;npm install -D tailwindcss postcss autoprefixer初始化 Tailwind 配置文件&#xff1a;npx tailwindcss init这会生成 tailwind.config.js。 步…

【英语语法】基本句型

目录 前言一&#xff1a;主谓二&#xff1a;主谓宾三&#xff1a;主系表四&#xff1a;主谓双宾五&#xff1a;主谓宾补 前言 英语基本句型是语法体系的基石&#xff0c;以下是英语五大基本句型。 一&#xff1a;主谓 结构&#xff1a;主语 不及物动词 例句&#xff1a; T…

隔离DCDC辅助电源解决方案与产品应用科普

**“隔离”与“非隔离的区别** 隔离&#xff1a; 1、AC-DC&#xff0c;也叫“一次电源”&#xff0c;人可能会碰到的应用场合&#xff0c;起安全保护作用&#xff1b; 2、为了抗干扰&#xff0c;通过隔离能有效隔绝干扰信号传输。 非隔离&#xff1a; 1、“安全特低电压&#…

DS-SLAM 运动一致性检测的源码解读

运动一致性检测是Frame.cc的Frame::ProcessMovingObject(const cv::Mat &imgray)函数。 对应DS-SLAM流程图Moving consistency check的部分 把这个函数单独摘出来&#xff0c;写了一下对两帧检测&#xff0c;查看效果的程序&#xff1a; #include <opencv2/opencv.hpp…