Linux:进程状态

目录

1. 进程状态

 1.1 并行和并发

1.2 时间片

1.3 运行状态

1.4 阻塞(等待)状态

1.5 挂起状态

2. Linux的进程状态

2.1 运行状态

2.2 sleep状态

2.3 Stop状态

2.4 X和Z状态

2.5 孤儿进程

 


1. 进程状态

如果你看任何一本关于操作系统的教材,都会有类似下面进程状态转换图。但具体的操作系统有Linux,windows等,所以操作系统教材需要上升到一个更高的维度,抽象出所有操作系统的共性并阐述它。因此,我们难以理解下面的进程状态转换图,许多概念很陌生。

本文会从Linux操作系统入手,讲解其进程的状态。

067a8aa59472461193fddf11dbcb273d.png

 

 1.1 并行和并发

并行:多个进程在多个CPU下分别,同时进行运行,这称之为并行。

并发:多个进程在一个CPU下采用进程切换的方式,在一段时间内,让多个进程都得以推进,称之为并发。

单个CPU执行进程代码,不是把进程代码执行完毕,才开始执行下一个进程代码。而是给每一个进程分配一个时间片,基于时间片,进行调度轮转

  • 当您使用C/C++编写一个死循环代码并运行时,您可能会观察到程序并不会导致整个系统卡顿。这是因为现代操作系统的调度机制发挥了作用。具体来说,CPU在执行该死循环程序时,并不是无休止地持续运行,而是在用完了分配给该程序的时间片之后,操作系统会包括保存当前程序的状态(代码和数据),然后调度另一个进程来执行。

 

1.2 时间片

时间片(Time Slice)是一种在操作系统中使用的调度技术。在多任务操作系统中,为了能够公平且高效地共享处理器(CPU)时间,操作系统将一个进程的运行时间分割成许多小的时间段,每一个时间段就是一个时间片。

  • 那如果我在听音乐和看视频,为什么我们不会感到卡顿?因为每个时间片通常极为短暂,仅存在于毫秒级别,而CPU的处理速度则是惊人的,每秒能够执行几亿甚至几十亿次基本操作。这样的高速处理能力,使得CPU在各个任务之间迅速切换,而用户几乎无法察觉到这种频繁的交接。

 

上面基于时间片轮转(time-slicing)技术的操作系统,叫做分时操作系统,主要应用于民用级别计算机。因为这类操作系统的进程调度优先级没有明显的区分,所以要求能调度多个进程,并追求调度任务公平

与之相对的就是实时操作系统,它更注重任务的及时性和可靠性。主要应用于那些对时间敏感、对任务完成时间有严格要求的领域,如工业控制、航空航天、医疗设备、汽车电子等。

 

1.3 运行状态

ca32f4f7806941d28370408cb5f735b6.png

进程 = 内核数据结构(task_struct) + 程序的代码和数据

task_struct结构体对象不仅记录了进程的各种属性,还有某种数据结构来连接多个进程,完成管理所有进程的工作。

6ec03bdfcf9e49c08d8f014b0840a253.png

当一个程序启动变成进程,先会创建task_struct结构体对象,再将该程序的代码和数据从磁盘加载到内存当中。该进程的pid为1.

此时,操作系统会有一个运行队列结构体,叫做runqueue。它里面有许多属性,其中有个变量类型是task_struct结构体类指针。该指针会连接内存中的task_struct对象。

如果还有更多程序启动,假设里面存在结构体指针,那么新进程结构体对象会被已存在进程对象中结构体指针连接。这样就被runqueue结构体对象管理起来。

当CPU要调度pid为1的进程时,我们假设使用最简单的FIFO(先进先出)调度算法,那么CPU会到runqueue队列中找到第一个task_struct对象,获取该进程main函数地址和数据,放到CPU的寄存器中,并执行该进程。

85180c12d6904213ab0764f15ada028c.png

当CPU调度时间到达该pid为1进程的时间片,该进程会自动记录执行到那行代码和数据,操作系统会将该结构体对象从runqueue队列中剥离下来,连接到最后一个task_struct结构体对象的后面。之后,CPU获取队头的进程代码和数据,执行该程序。

如此循环往复,就完成了基于时间片的轮转调度。

我们也可以得出一个结论,在Linux操作系统中,只要进程在运行队列中,该进程的状态就叫做运行状态。此时表明进程已经准备好了,可以随时被CPU调度。所以不是进程正在被执行,进程状态才是运行状态。一般来说,就绪状态和执行状态可以合二为一,叫做运行状态。

 

1.4 阻塞(等待)状态

除了CPU内部设备,计算机还有许多外部设备,如磁盘、显示器、键盘和网卡等。

  • 操作系统作为管理计算机软硬件资源的核心软件,在处理各类对象时,始终遵循“先描述,后组织”的基本原则。为此,操作系统定义了一个名为“device”的结构体,该结构体内包含了设备的类型、状态等关键属性。
  • 同时,为了有效地组织和管理这些设备,结构体还会包含某种数据结构。我们这里结社结构体中还包括了一个指向同类结构体的指针,通过链表这种数据结构,将所有设备对应的结构体对象串联起来,形成一个有序的设备管理链。

c482cb689da647668c63ce7d98a6615a.png
如图所示,当CPU调度到标识为PID 1的进程时,若该进程执行到scanf函数并等待用户从键盘输入数据,此时进程将处于等待键盘输入的状态。由于用户输入数据所需的时间通常会远远超过该进程分配的时间片,CPU不可能因此暂停其他进程的调度。因此,该进程会变为阻塞状态,那怎么理解阻塞状态呢?

 

2244475f8aea4714b239a70eaba94b11.png

上面我们解释了操作系统管理硬件时,也会为硬件创建一个结构体。该结构体中会包含一个task_struct结构体指针,叫做waitqueue,即等待队列。操作系统会把等待键盘输入的进程结构体对象从runqueue剥离下来,键盘结构体对象的waitqueue指针会连入该task_struct对象。

如果有其他进程需要等待某个硬件设备的数据,该硬件设备结构体中会存在一个等待队列,连接进程的结构体对象。

因此,我们可以得出以下结论:当进程处于运行状态或阻塞状态时,其对应的PCB将被置于特定的队列中。本质上,进程始终在访问某种硬件资源,当它正在使用CPU资源时,我们称其为运行状态;而当它等待其他外部设备资源时,则处于阻塞状态。

 

1.5 挂起状态

c2e1889c54b640dd921bcb3062fbc585.png

当内存资源严重不足时,操作系统会将在处于阻塞状态的进程直接放到磁盘中的一个区域,这个区域叫做swap分期,此时进程的状态叫做阻塞挂起状态。

但是由于处于运行状态的进程太多而导致内存资源不足,而运行队列尾部的进程一段时间都不会被调度,操作系统就会将这些进程放到磁盘中的swap分区,此时进程状态叫做运行挂起状态。这是极端的操作,风险较大,一般不会出现。

 

 

2. Linux的进程状态

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
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 */
};

上面是Linux源代码,表示进程的状态。分别有“R”“S”“D”“T”等状态。将会一个个展示。

 

 

2.1 运行状态

#include <stdio.h>
#include <unistd.h>int main()
{while(1){}return 0;
}

5c5afa2abae5486088a3155706ee6539.png

e994a125ad1a4c0587b8ba3c116f3282.png

我们写个死循环,正常来说应该是运行状态。使用ps指令查询myproc进程的状态,会发现进程状态就是R+,其中“+”符号表示在前台运行。

 

 

2.2 sleep状态

#include <stdio.h>int main()
{int cnt = 0;while(1){scanf("%d", &cnt);}return 0;
}

4826ec861b444e55b43f07272f0ab43f.png

fe071652e5a04e34aa51a6fdab07c533.png

当我们写一个scanf函数,进程会等待键盘数据,此时的进程状态是阻塞等待状态。使用ps指令查询myproc进程,会发现myproc程序的状态是S。对应最开始给出的Linux进程状态的解释是sleeping,即休眠。所以,Linux中的阻塞状态叫做休眠。

 

 

18fa678ff6194e72873a20745fdb7a9a.png

5809c5ae2c654ebfa0787da374e2b31f.png

当我们想终止休眠状态下的进程,我们可以使用kill指令,发送信号终止进程。这种休眠状态叫做可中断睡眠,也叫浅睡眠。

与之相对的就是不可中断睡眠,即深度睡眠,就是disk sleep状态。disk sleep意思是磁盘休眠状态。当系统处在磁盘级拷贝,会进行大量的读写操作,此时无法使用kill指令终端进程。

 

 

2.3 Stop状态

#include <stdio.h>
#include <unistd.h>int main()
{int cnt = 0;while(1){printf("hello world, cnt: %d\n", cnt++);sleep(1);}return 0;
}

5209567f0ef14dae96a2ddb03927fb3c.png

79b88837d1a644f588f8b866d8230854.png

 我们写一个死循环打印变量的程序,运行起来,会发现处于S状态。这是因为printf本质是向内存缓冲区写入数据,再输出到显示器上,而输入输出的时间相比于毫秒级的时间片很慢,所以百分制九十九以上的时间都在显示器的等待队列中。

 

2ba264934f0c42c5a9a14e9bf2a4249c.png

ac7814f142b549efb4236db47fec1d98.png

21e8369cc403448d8cf59c0f3c76a795.png

我们可以使用kill指令,其中19号选项就是发送暂停信号。查看进程状态就是T,运行的进程也会出现终端,有Stopped提示。

 

4083ccc3a2a14521a89dcf3754bb8870.png

e18ae1ba65314171bc293542458a19ac.png

如果想继续运行进程,可以使用kill指令的18选项,使暂停的进程继续启动。

 

8f341e0c365242d183fa6ee337f9f95d.png

48082b70adf1445baf06ef4044548671.png

但是你会发现该进程的状态变量了S,没有“+”符号,说明进程在后台运行。此时我们无法使用Ctrl+C终止程序,但可以使用kill指令9号选项终止程序。而一般出现T状态,说明进程做了非法饭不知名的操作。

后台进程是指在操作系统中,在后台独立运行的程序,它们不直接与用户交互。在Linux系统中,后台进程通常是那些不需要即时用户输入且执行时间较长的任务。这些进程在执行时,用户可以继续使用终端进行其他操作。相对应地,在Windows操作系统中,当用户将一个耗时的任务,如下载大文件,最小化其窗口后,该任务便在后台运行。此时,用户可以切换到其他应用程序,进行不同的工作,而下载任务则在后台安静地继续进行

 

2.4 X和Z状态

X状态指的是dead,就是死亡状态,顾名思义,指的是进程被终止了。

5cd75a9180b7401092e7480c4efe62cd.png

创建一个进程,是为了完成一个任务。父进程是要知道他的子进程完成任务的情况,子进程在退出时会记录一个退出信息。在Linux中,查看一个进程退出信息,可以使用echo $?指令获取。

执行ls指令,相当于执行一个程序,查看退出信息为0,说明进程执行任务成功。当使用ls查看不存在的文件,会报查不到该文件的错误,此时再查看退出信息就是非0的。我们所写的main函数一般都会返回0,就是告诉系统该任务执行成功。

 

 

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main()
{printf("父进程运行,pid: %d,ppid: %d\n",  getpid(), getppid());pid_t id = fork();if (id == 0){//子进程int cnt = 10;while(cnt){printf("我是子进程,我的pid: %d,ppid: %d, cnt: %d\n",getpid(), getppid(), cnt);sleep(2);cnt--;}}else {//父进程while(1){printf("我是父进程,我的pid: %d,ppid: %d\n", getpid(), getppid());}sleep(1);}return 0;
}

我们写一个代码,使用fork函数创建子进程,子进程执行几十秒就结束,父进程不退出。

 

 

c026a3b225fc4aceaac6787712f5e17f.png

cf676e714dfa4f429bfbd73284f3dc50.png 我们执行该程序,并使用一个循环指令查看相关进程信息。发现父子进程都处于S状态。

 

fcf085cba6c34aa0a0f95a61e37e4d68.png

f1c0e8268d8449ae89f702ab8852e78a.png

当子进程执行完毕退出时,他的状态变量Z状态。其中Z状态指的是zombie,即僵尸状态。当一个程序退出,代码和数据都在内存都销毁了,还会剩下task_struct对象,等着父进程回收查看。

退出的子进程还剩下结构体对象,如果没有父进程接受管理,它会一直是僵尸状态,不断消耗内存,会造成内存泄漏!

 

 

2.5 孤儿进程

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>int main()
{printf("父进程运行,pid: %d,ppid: %d\n",  getpid(), getppid());pid_t id = fork();if (id == 0){//子进程while(1){printf("我是子进程,我的pid: %d,ppid: %d\n",getpid(), getppid());sleep(1);}}else {//父进程int cnt = 10;while(cnt > 0){printf("我是父进程,我的pid: %d,ppid: %d, cnt: %d\n", getpid(), getppid(), cnt--);sleep(1);}sleep(1);}return 0;
}

我们写一份代码,父进程退出,子进程死循环不退出。

 

 

196dfb65cc27428e951e9c49ec2892a6.png

402b7766a4e049eb956e868c2910db8c.png

06d46cdeab524df3be921a0428d657e3.png

父进程没退出前,父子进程都处于S状态。当父进程退出,子进程还在运行,状态没变,但是PPID为1,说明他的父进程变为pid为1的进程。

 

6e576276f87f42eb9f18d297d61b2f6a.png

通过top指令查询进程信息,可以看到pid为1的进程,指令叫做systemd,即系统。说明子进程被系统进程领养,我们称这种进程为孤儿进程。

 

 


创作充满挑战,但若我的文章能为你带来一丝启发或帮助,那便是我最大的荣幸。如果你喜欢这篇文章,请不吝点赞、评论和分享,你的支持是我继续创作的最大动力!

db7aef8aedd94befa53ef752e3298159.png

 

 

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

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

相关文章

Oracle或者PL/SQL导入pde文件

目录 pde文件使用pl/sql developer的 tools-> import tables-> pl/sql developer来导入&#xff1b;

Ubuntu20.04下安装多CUDA版本,以及后续切换卸载

本方案的前提是假设机子上已经有一个版本的cuda&#xff0c;现在需要支持新的torch2.1.2和torchvision0.16.2&#xff0c;于是来安装新的cuda 一、选择版本 如果我想安装支持torch2.1.2的cuda版本&#xff0c;到官网&#xff08;https://pytorch.org/get-started/previous-ve…

scrapy案例——豆瓣电影Top250的爬取

项目&#xff1a;豆瓣电影Top250的爬取 案例需求&#xff1a; 1.使用scrapy爬虫技术爬取豆瓣电影Top250的电影数据&#xff08;包括排名、电影名称、导演、演员、url、评分&#xff09; 2.实现分页爬取&#xff0c;共十页 3.将爬取下来的数据保存在数据库中 案例分析&…

利用由 Search AI 提供支持的自动导入功能加速 Elastic Observability 中的日志分析

作者&#xff1a;来自 Elastic Bahubali Shetti 通过自动化自定义数据集成&#xff0c;以创纪录的速度将日志迁移到 AI 驱动的日志分析。 Elastic 正在通过自动提取自定义日志来加速采用 AI 驱动的日志分析&#xff08;AI-driven log analytics&#xff09;&#xff0c;随着基…

Java程序设计:spring boot(2)

目录 1 Spring MVC 零配置创建与部署 1.1 创建Spring MVC Web⼯程 1.2 pom.xml 添加坐标相关配置 1.3 添加源代码 1.4 添加视图 1.5 SpringMVC 配置类添加 1.6 入口文件代码添加 1.7 部署与测试 2 Spring Boot 概念&特点 2.1 框架概念 2.2 框架特点 2.3 Spring…

作业2-线性回归的Matlab代码实现

一、前言 相关配置&#xff1a;Matlab 2020a&#xff08;版本的影响应该不大&#xff0c;.m代码基本都能运行&#xff0c;个人感觉就是Simulink对版本的要求高一些&#xff09; 二、任务描述 基于近两节课的理论推导&#xff0c;用代码实现线性回归&#xff0c;并对预测结果进…

【vue】vue-router_ vue3路由管理器

代码获取 vue-router_ vue3路由管理器 ⼀、基本介绍 1. 单⻚应⽤程序介绍 1.1 概念 单⻚应⽤程序&#xff1a;SPA(Single Page Application)是指所有的功能都在⼀个HTML⻚⾯上实现 1.2 具体⽰例 单⻚应⽤⽹站&#xff1a; ⽹易云⾳乐 https://music.163.com/ 多⻚应⽤⽹…

linux环境下C程序的编译过程以及makefile的简单使用

在windows下&#xff0c;很多用来进行编程软件对于写好的文件&#xff0c;点击编译即可生成想要文件。如.exe可执行文件&#xff0c;.hex文件或者.bin文件等等。软件为我们省略了很多事。但是对于linux初学者来说&#xff0c;初次接触linux系统&#xff0c;面对命令行黑框框有点…

git-合并连续两次提交(一个功能,备注相同)

前言&#xff1a; 场景是这样&#xff0c;由于我是实现一个功能&#xff0c;先进行了一次commit,然后我发现写的有些小问题&#xff0c;优化了一下功能并且把代码优化了一次&#xff0c;于是又提交了一次。两次的提交都是以相同的备注&#xff08;当然这个无所谓&#xff09;&a…

智能时代摩托车一键启动无钥匙进入感受科技前线

向智能化与高性能迈进,技术创新与绿色转型引领摩托车行业智能化出行。 摩托车一键启动无钥匙进入功能是一种先进的车辆控制系统&#xff0c;它允许驾驶员在不使用传统机械钥匙的情况下&#xff0c;通过智能感应技术自动解锁和启动摩托车。这种系统通常包括一个智能钥匙&#x…

【前端】如何制作一个自己的网站(11)

接上文。 除了前面的颜色样式外&#xff0c;字体样式和文本样式也是网页设计中的重要组成部分。 合适的字体和文本排版&#xff0c;不仅可以使页面更加美观&#xff0c;也可以提升用户体验。接下来&#xff0c;我们先来看看CSS如何设置字体样式。 字体样式 同时设置了字体样…

Python SQL 注入攻击及其防护措施:编写安全的数据库查询

Python SQL 注入攻击及其防护措施&#xff1a;编写安全的数据库查询 SQL 注入&#xff08;SQL Injection&#xff09;是一种常见且危险的安全漏洞&#xff0c;攻击者通过操纵应用程序的数据库查询输入&#xff0c;执行未经授权的操作&#xff0c;可能会导致数据库数据泄露、篡…

闯关leetcode——136. Single Number

大纲 题目地址内容 解题代码地址 题目 地址 内容 Given a non-empty array of integers nums, every element appears twice except for one. Find that single one. You must implement a solution with a linear runtime complexity and use only constant extra space. …

leetcode30:串联所有单词的字串

给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如&#xff0c;如果 words ["ab","cd","ef"]&#xff0c; 那么 "abcdef…

thinkpad E14 GEN5 加内存

1、正面 2、背面 3、角落 松掉所有螺丝后&#xff0c;用塑料撬片沿着角落开始撬。把所有的卡口都撬开就可以了。 4、内存盖子 取下背板&#xff0c;就看到内存区域了。上面覆盖了一个散热金属盖子。 拿掉金属盖子。 5、内存卡口 我的这代笔记本是板载16G DDR4 3200内存&…

Java 类和对象详解(下)

个人主页&#xff1a;鲤鱼王打挺-CSDN博客 目录 &#x1f497;前言&#xff1a; &#x1f4af;一.static关键字 1. 为什么要使用static 2. static 修饰成员变量&#xff1a; 3. static 修饰成员方法&#xff1a; ​编辑 4. 静态代码块 5.静态导入包 &#x1f4af;二.…

C++进阶——set和map

目录 前言 一、set 1.set的基本介绍 2.set的使用 2.1构造与迭代器 2.2插入 2.3删除 2.4查找 2.5获取需要的区间 2.6一些使用示例 3.set和multiset的区别 4.set相关oj题目 二、map 1.map的基本介绍 2.map的使用 2.1构造与迭代器 2.2增删查以及获取区间 2.3数据…

【C语言】strtok、strerror函数

1、strtok函数使用 注意&#xff1a;使用strtok时包含头文件&#xff1a;string.h strtok函数原型&#xff1a; char* strtok(char* str, const char* sep); &#xff08;1&#xff09;sep参数指向一个字符串&#xff0c;定义了用作分隔符的字符集合。 &#x…

xlsx xlsx-style-vite 实现前端根据element 表格导出excel且定制化样式 背景 列宽等

前言 先看下最终效果图吧&#xff0c;需要的可以参考我的实现方式 这是最终导出的表格文件 类似这种的&#xff0c;特定单元格需要额外标注&#xff0c;表头也有月份然后细分的&#xff0c;表格组件是这样的 注意 别使用xlsx-style 这个库&#xff0c;太多问题了&#xff0c;…

优阅达携手 Theobald 亮相新加坡科技周,助力企业 SAP 数据集成与应用

针对不同用户需求量身定制解决方案&#xff0c;帮助企业轻松应对从数据提取到分析、从开发到流程管理的 SAP 数据挑战。 上周&#xff0c;2024 新加坡科技周在滨海湾金沙会议展览中心圆满落幕。在为期两天的活动中&#xff0c;七大专题展览同时进行&#xff0c;超过 2,000 家…