【Linux】第十三站:进程状态

文章目录

  • 一、进程状态
    • 1.运行状态
    • 2.阻塞状态
    • 3.挂起状态
  • 二、具体Linux中的进程状态
    • 1.Linux中的状态
    • 2.R状态
    • 3.S状态
    • 4.D状态
    • 5.T、t状态
    • 6.X状态(dead)
    • 7.Z状态(zombie)
    • 8.僵尸进程总结
    • 9.孤儿进程总结

一、进程状态

在我们一般的操作系统学科中,它的进程状态是:运行、阻塞、挂起

image-20231107172143988

上图中的新建状态就是,一个进程刚刚创建出来的时候,即PCB刚刚创建出来

终止状态就是已经不用了,代码被运行完了

运行状态就是正在被调度的状态

1.运行状态

如下图所示,我们知道,我们的程序在运行的时候,想运行的进程是非常之多的,而CPU在极端场景下只有一个。所以这么多进程就要存在竞争。而因为调度器的存在,就让他们较为均衡的使用

image-20231107174128101

所以每一个CPU都要维护一个它自己的运行队列(struct runqueue),它可以对这些进程做出调度

struct runqueue
{//运行队列struct task_struct* head;struct task_struct* tail;
};

如下图所示,CPU就可以直接从运行队列中拿到一个进程进行执行。

image-20231107182529959

这就叫做进程在CPU上进行排队,该队列叫做运行队列。

而调度器就是一种函数,可以将这个运行队列作为参数传进来,从而就可以找到所有在排队的进程。

而在运行队列中的所有进程,都是R状态,即运行态。

image-20231107183024704

运行态就是我已经准备好了,随时可以被调度!!!只要处于运行队列,都是运行态

当我们创建好一个新进程的时候,只要它入队,就是运行态,只要等调度它就行了

问题: 一个进程只要把自己放到CPU上开始运行了,是不是要一直执行完毕,才把自己放下来?

不是!就比如我们前面所写的while死循环代码。

为了防止某个进程上去以后就下不来了,陷入了死循环,所以每一个进程就有一个时间片的概念,它也是PCB里面的一个数值。比如说是10ms,一旦超过这个10ms,计算机就要强制的把这个进程从CPU上扒下来,放到队列尾部。

所以在一个时间段内,所有的进程代码都会被执行!

对于上面着这种我们也叫做并发执行。

所以大量的把进程从CPU上放上去,拿下来的动作----也叫做进程切换

2.阻塞状态

我们知道操作系统的管理的核心就是先描述、在组织。

如下是我们的操作系统的结构

image-20231107185300186

操作系统要管理下面的设备、外设。就需要先描述后组织的方式

对于进程管理是隶属于软件的,而对于硬件的管理也可以用类似的方式。

struct dev
{int type;int status;struct task_struct* waitqueue;//............
};

image-20231107185722691

假设现在有一个进程,它的任务是从键盘中读取数据

image-20231107190329525

我们现在不给他输入,那么它就会等待,而且它也无法放入运行状态中,因为它当前的软硬件资源没有就绪。

所以它就会等待某种资源,而这在操作系统中只需要将他放入到键盘所对应的等待队列中

当未来还有数据需要进行输入的时候,这时候就需要往后面排队了

image-20231107190708854

同理每一个设备都可能这样的情况。

当未来我们这个键盘给这个进程数据的话,那么它就就绪了,可以进入运行队列了,从而CPU就可以去调度了

所以我们将这个正在等待排队的进程称作阻塞状态,每个这样的设备都有一个等待队列。当进程从读取到数据的时候,就会唤醒:从阻塞状态改为R状态

3.挂起状态

我们现在有一个设备叫做磁盘

image-20231107191728197

如果我们当前有多个进程正在等待键盘这个资源,可是这个键盘的资源一直在就绪,因为没有人摁它。

所以这些进程,只能以阻塞状态在等待队列中等待

可是如果,在等待的时候,操作系统的内存资源严重不足了。

所以操作系统就需要在保证正常的情况下,省出来内存资源

以阻塞状态为例,只要它没有运行的那一刻,我们当前进程的代码和数据其实是在内存里处于空闲的,没有被使用的。

所以此时操作系统会将这些进程的PCB给保留,将这个代码和数据放到磁盘外设中。

所以就相当于这个进程只有一个PCB在排队,而它自己的代码和数据在外设里面。

当这个进程就绪了,要放到运行队列了,在考虑将这个代码和数据重新放回来。

这个过程就是换出和换入的过程

image-20231107192537269

如果一个进程只有它的自己的PCB在,而代码和数据都换出了,并没有在内存当中,那么此时就是挂起状态

如果所有的进程都这样做,那么瞬间操作系统就能腾出一大块空间

其实我们现在场景下所说的挂起应该称作阻塞挂起状态

当然还有运行挂起,就绪挂起…等等,我们都不去考虑

二、具体Linux中的进程状态

1.Linux中的状态

如下所示,是linux系统中的状态。我们可以看到与前面传统的操作系统教材中所说的状态还是有很大的差别的。

static const char * const task_state_array[] = {"R (running)", /* 0 */"S (sleeping)", /* 1 */"D (disk sleep)", /* 2 */"T (stopped)", /* 4 */"t (tracing stop)", /* 8 */"X (dead)", /* 16 */"Z (zombie)", /* 32 */
};

2.R状态

Linux中R状态就是运行状态

我们先看下面的代码

image-20231108202659112

当我们运行的时候,我们可以去查看它的运行状态

image-20231108202145737

我们也可以在重新多运行一下

image-20231108203025980

我们注意到的现象是,大部分情况下都是S状态,极少部分情况是R状态

我们我们的代码明明就是在运行,却显示是S状态呢?

我们先将代码稍作修改

image-20231108203251127

然后在运行

我们就可以注意到,现在都是R状态了

image-20231108203328945

那么这是为什么呢?

这是因为我们用我们自己的感受去揣测了CPU的速度

因为我们刚刚一直在printf,需要访问外设(显示器)。我们的设备并不一定能处于一个直接写入的状态,所以我们的这个进程有非常大的概率在等待

而我我们将printf去掉以后,一直在快速的循环,就一直处于运行态了。

我们也可以用top命令,就相当于任务管理,可以随时查看进程

image-20231108204709165

同时我们也可以注意到,我们前面使用ps命令查看的时候,状态后面有个+号。这个加号代表着这个进程在前台运行。(前台运行意味着我们继续输入其他指令是没有任何反应的)

如果我们要在后台运行一个进程,我们在后面加上一个&即可

image-20231108205207410

像这种后台进程,我们只能通过kill命令来杀掉了

image-20231108205313990

3.S状态

我们将代码改为如下

image-20231108205532082

这个时候我们查到的进程大概率都是S状态

image-20231108210315836

这个就是因为CPU太快了,而这个进程要访问外设,这就显得太慢了

不过我们还可以用下面这个例子会更加直观

image-20231108211458521

image-20231108211604348

而这个状态就和我们操作系统学科中的是一样的。

也就是说linux中的S状态就是操作系统中的阻塞状态

而像我们操作系统中的一般都是阻塞状态,即在等待某种资源就绪。

image-20231108211907794

所以所谓的阻塞状态,就是在等待某种资源就绪

像我们前面的scanf就是在等键盘输入,像printf就是在等显示器就绪

4.D状态

在linux中,除了S状态是阻塞状态以外,还有一种状态也是阻塞状态,D状态,不过它也叫做深度睡眠;而S状态我们也称为浅度睡眠

两者的区别就是,S状态,即浅度睡眠是可以被唤醒的

也就是说,虽然这个进程还在继续,但是我们可以用kill去杀了他,即随时可以相应外部的变化

像下面的这种就是处于浅度睡眠的

image-20231108212741385

而深度睡眠就是不可以被唤醒的

D状态(disk sleep磁盘休眠)

比如下面这个例子

假设现在有一个进程,它想向磁盘中写入1GB数据

但是这个过程是需要画出一定的时间的。而在这段时间内,这个进程就必须得在这里等磁盘把数据全部写完,等他反映的结果。

如果此时OS的内存压力很大,它现在已经把能置换的资源全部置换了。那么操作系统如果看这个进程不爽,直接就会把他杀掉

也就说,当OS内存压力很大的时候,就会杀掉一些不重要的进程。

即如果OS可以的话,那就直接去用内存,如果扛不住了,那就尝试置换,如果还是扛不住,那就只能杀掉进程了。

这时候,如果一旦磁盘写入失败,还发现了进程已经被杀了,此时就无法回应给进程了,磁盘也无法做出决策。这时候就看具体硬件的做法了,有的硬件会直接丢掉这个数据,有的会尝试在写一次。

如果被丢失的这1GB数据很重要,那么就糟糕了


为了解决上面这个问题,所以我们需要保证让进程在等待磁盘写入完毕期间,这个进程不能被任何人杀掉,就可以了

所以说当一个进程正在等待磁盘写入数据的时候,不能设置为S状态,必须得设置为D状态,D状态就不能被任何人所杀掉

当这个数据全部写完以后,这个进程再将D状态恢复为R状态

同时也意味着,如果操作系统里面只要出现一个D状态,那么操作系统已经即将崩溃了

深度睡眠不可以被杀死的原因就是:不相应任何请求

如果我们想要模拟一下的话,可以使用dd命令,这个可以模拟高IO的情况

5.T、t状态

T状态我们称为暂停状态,也叫做stop状态

我们使用如下代码

image-20231108220000628

当我们运行的时候,是处于S状态的

image-20231108220207981

在linux中有一个信号的东西,如下我们之前杀掉进程用的是9号信号

image-20231108220253917

然后在这里我们可以给他发送18和19号信号

19号进程SIGSTOP它的作用将一个进程给暂停,如果我们将他暂停后想重新运行起来那就发送18号信号SIGCONT

image-20231109121015354

如上就是变成了T状态了,当然也可以用18号信号将他给继续跑起来

image-20231109121113454

我们可以看到,这个先暂停后再恢复,它就没有了+号了,就说明它已经变成了后台运行了

那么这个T状态和S状态有什么区别呢?

其实是有的,否则也不会分成两种状态了。

S状态一定是为了等待某种资源就绪的,而T状态暂停后当然也可以等待某种资源就绪,当然也有可能是为了等待其他事件发生后才继续执行,它是不接收除了某些信号之外的其他请求的。也就是说,T状态有可能我们只是单纯的想让他暂停一会。

不过我们暂时可以将他理解为也是某种阻塞状态

如下所示,当我们在使用gdb调试的时候,这个程序就处于t状态(T、t我们暂时不做区分)

image-20231109122506216

6.X状态(dead)

所谓的X状态就是我们前面操作系统中的终止态,就相当于一个进程结束了。

然后就可以将这个进程放到一个垃圾回收的队列中,最终操作系统就会将这些回收掉

7.Z状态(zombie)

当一个进程死亡的时候,在死亡之时不会立即进入X状态,而是会先进入Z状态(僵尸状态)

即一个进程在退出时,操作系统会先将这段信息维持一段时间。这段时间就是僵尸状态

而一个进程在退出时候,只有父进程最关心这个信息

我们可以用如下代码来进行验证。在如下代码中,子进程循环结束以后直接退出。而父进程中并没有针对子进程做出任何事情,也就意味着,一旦子进程退出了,这个父进程还在,但是啥也不干,也就意味着子进程将一直维持一种僵尸状态,它要一直等父进程来获取它的退出信息

image-20231109125816923

同时运行这段代码和下面的指令

while :; do ps ajx | head -1 && ps ajx | grep mytest;sleep 1 ; done

运行结果如下所示

image-20231109130926824

我们可以看到,当子进程退出了以后,它这个进程处于Z状态了,并且后面出现了defunct这个单词,它的意思是无效的,死者,死人

这就是僵尸状态的进程

进程一般退出的时候,如果父进程没有主动回收子进程信息,子进程会让自己一直处于Z状态,进程的相关资源尤其是task_struct结构体不能被释放

我们把处于Z状态的进程也称之为僵尸进程

内存一直会被占用着,就会发生内存泄漏了

不过我们还要注意

image-20231109131637979

当我们将程序将父进程也结束的时候,子进程也被退出了,它也没有处于僵尸状态。

这是因为,父进程退出的时候,它也有自己的父进程bash,bash瞬间将父进程给回收了,所以没有看到父进程处于僵尸状态。

前面是子进程先退出的案例,我们在看一个父进程先退出的案例

image-20231109133336929

运行结果如下

image-20231109133549456

我们发现当父进程挂掉以后,它的子进程的父进程变为了1

那么这是为什么呢?我们先看一下1号进程是什么

image-20231109135305345

可以看到就是系统的进程

image-20231109135441730

即1号进程就是操作系统本身

所以我们得到以下结论:

如果父子进程中,父进程先退出,子进程的父进程会被改为1号进程(操作系统)

父进程是一号进程,我们将这个进程称为孤儿进程

该进程被系统所领养!

那么为什么要被领养呢?

因为孤儿进程未来也会退出,也要被释放。

那么为什么不让bash领养呢?

bash做不到,bash只是创建的它的子进程,无法管理它的孙子进程。而操作系统可以直接从内核去释放掉

8.僵尸进程总结

  • 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎
    么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话
    说,Z状态一直不退出,PCB一直都要维护?是的!
  • 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构
    对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空
    间!
  • 内存泄漏?是的!

9.孤儿进程总结

  • 父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
  • 父进程先退出,子进程就称之为“孤儿进程”
  • 孤儿进程被1号init进程领养,当然要有init进程回收

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

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

相关文章

Linux学习第39天:Linux I2C 驱动实验(三):哥俩好

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 linux I2C驱动试验整节的思维导图如下: 本节笔记主要学习试验程序的编写及运行测试。其中试验程序的编写主要包括修改设备树、AP3216驱动编写及编写测…

rocksdb 中 db_bench 的使用方法

硬件要求 硬件要求如表1所示。 表1 硬件要求 项目 说明 CPU 12 * AMD Ryzen 5 5500U with Radeon Graphics 内存 DDR4 磁盘 HDD 软件要求 软件要求如表2所示。 表2 软件要求 项目 版本 说明 下载地址 CentOS 7.6 操作系统。 Download kernel 4.14.0 内核。…

pytorch优化器详解

1 什么是优化器 1.1 优化器介绍 在PyTorch中,优化器(Optimizer)是用于更新神经网络参数的工具。它根据计算得到的损失函数的梯度来调整模型的参数,以最小化损失函数并改善模型的性能。 即优化器是一种特定的机器学习算法&#…

磁盘的分区、格式化、检验与挂载 ---- fdisk,mkfs,mount

磁盘的分区、格式化、检验与挂载 磁盘管理是非常重要的,当我们想要再系统里面新增一块磁盘使用时,应执行如下几步: 对磁盘进行划分,以建立可用的硬盘分区 (fdisk / gdisk)对硬盘分区进行格式化&#xff0…

javaScript爬虫程序抓取评论

由于评论区目前没有开放的API接口,所以我们不能直接通过编程获取到评论区的内容。但是,我们可以通过模拟浏览器的行为来实现这个功能。以下是一个使用Python的requests库和BeautifulSoup库来实现这个功能的基本思路: import requests from bs…

服务器往客户端发送字符串的网络编程

服务器主要就是能够打开命令行提供的网络端口&#xff0c;然后一有客户端连接上&#xff0c;就会向客户端发送Welcome to Our Server!这段话。 服务器代码serverSayWelcome.c的代码如下&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.…

MySQL库的库操作指南

1.创建数据库 一般格式&#xff1a;create database (if not exists) database1_name,database2_name...... 特殊形式&#xff1a; create database charset harset_name collate collate_name 解释&#xff1a; 红色字是用户自己设置的名称charset&#xff1a;指定数据…

网络安全——

文章目录 网络安全TCP/IP与网络安全网络安全构成要素加密技术基础 网络安全 TCP/IP与网络安全 起初&#xff0c;TCP/IP只用于一个相对封闭的环境&#xff0c;之后才发展为并无太多限制、可以从远程访问更多资源的形式。因此&#xff0c;“安全”这个概念并没有引起人们太多的…

FL Studio21.2宿主软件中文免费版下载

纵观当下宿主软件市场&#xff0c;正值百家争鸣、百花齐放之际像Mac系统的Logic Pro X、传统宿主软件代表Cubase、录音师必备Pro Tools、后起之秀Studio One等&#xff0c;都在各自的领域具有极高的好评度。而在众多宿主软件中&#xff0c;有这么一款历久弥新且长盛不衰的独特宿…

Linux应用开发基础知识——Framebuffer 应用编程(四)

前言&#xff1a; 在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。Frame 是帧的意 思&#xff0c;buffer 是缓冲的意思&#xff0c;这意味着 Framebuffer 就是一块内存&#xff0c;里面保存着 一帧图像。Framebuffer 中保存着一帧图像的每一个像素颜色值&#xff0c;假设…

【云栖2023】王峰:开源大数据平台3.0技术解读

本文根据2023云栖大会演讲实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a;王峰 | 阿里云研究员&#xff0c;阿里云计算平台事业部开源大数据平台负责人 演讲主题&#xff1a;开源大数据平台3.0技术解读 实时化与Serverless是开源大数据3.0时代的必然选…

【亚马逊云科技产品测评】活动征文|10分钟拥有一台AWS Linux系统

前言 在数字化时代&#xff0c;AWS云服务扮演着至关重要的角色。AWS&#xff08;Amazon Web Services&#xff09;是亚马逊公司旗下的云计算服务平台&#xff0c;为全球各地的企业、组织和个人开发者提供了一系列广泛而深入的云服务。 在AWS云服务中&#xff0c;计算、存储、数…

flink1.18.0 sql-client报错

报错 Flink SQL> select * from t1; [ERROR] Could not execute SQL statement. Reason: org.apache.flink.table.api.ValidationException: Could not find any factory for identifier kafka that implements org.apache.flink.table.factories.DynamicTableFactory in t…

小程序如何部署SSL证书

微信小程序开发前提必须拥有一本SSL证书&#xff0c;办理SSL证书之前确保好指定的微信小程序开发接口使用的域名&#xff0c;如果没有域名的提前申请好&#xff0c;并且到国内服务器提供商去办理备案。 了解微信小程序使用SSL证书的作用&#xff0c;包括以下三个方面&#xff1…

Mabitys总结

一、ORM ORM(Object/Relation Mapping)&#xff0c;中文名称&#xff1a;对象/关系 映射。是一种解决数据库发展和面向对象编程语言发展不匹配问题而出现的技术。 使用JDBC技术时&#xff0c;手动实现ORM映射&#xff1a; 使用ORM时&#xff0c;自动关系映射&#xff1a; &am…

<C++> list模拟实现

目录 前言 一、list的使用 1. list的构造函数 2. list iterator的使用 3. list capacity 4. list modifiers 5. list的算法 1. unique​ 2. sort 3. merge 4. remove 5. splice 二、list模拟实现 1. 设置节点类 && list类 2. push_back 3. 迭代器 重载 * 重载前置 …

小型洗衣机好用吗?最好用的迷你洗衣机

很多人会觉得小型洗衣机是智商税&#xff0c;没有必要专门买一个小型洗衣机来洗内衣&#xff0c;洗个内衣只需要两分钟的事情&#xff0c;需要花个几百块钱去入手一个洗衣机吗&#xff1f;然而清洗贴身衣物的并不是一件简单的事情&#xff0c;如果只是简单的搓洗&#xff0c;内…

基于安卓android微信小程序的物流仓储系统

项目介绍 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个开发过程首先对物流仓储系统进行需求分析&#xff0c;得出物流仓储系统主要功能。接着对物流仓储系统进行总体设计和详细…

安科瑞故障电弧探测器在建筑电气的设计与应用

安科瑞 崔丽洁 【摘要】&#xff1a;电气设备是建筑中不可缺少的一部分&#xff0c;具有较为重要的作用和意义&#xff0c;在应用过程中不仅能够提升建筑本身实用性能&#xff0c;而且可为消费者提供更加优良的生活环境。但设备一旦在运行过程中出现故障&#xff0c;不仅会影响…

JDBC(二)

第4章 操作BLOB类型字段 4.1 MySQL BLOB类型 MySQL中&#xff0c;BLOB是一个二进制大型对象&#xff0c;是一个可以存储大量数据的容器&#xff0c;它能容纳不同大小的数据。 插入BLOB类型的数据必须使用PreparedStatement&#xff0c;因为BLOB类型的数据无法使用字符串拼接写…