当前位置: 首页 > news >正文

【Linux操作系统】简学深悟启示录:进程状态优先级

文章目录

  • 1.进程状态
    • 1.1 运行态R
    • 1.2 阻塞态S(浅度睡眠)
    • 1.3 阻塞态D(深度睡眠)
    • 1.4 挂起态T
    • 1.5 挂起态t(追踪)
    • 1.6 终止态X
    • 1.7 僵尸态Z(僵尸进程)
    • 1.8 孤儿进程
  • 2.进程优先级
    • 2.1 查看优先级
    • 2.2 修改优先级
    • 2.3 优先级调度本质
  • 3.其他概念
  • 希望读者们多多三连支持
  • 小编会继续更新
  • 你们的鼓励就是我前进的动力!

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在 Linux 内核里,进程有时候也叫做任务),同时谁先运行也是很重要的

1.进程状态

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 系统里大致分为这几种

1.1 运行态R

在这里插入图片描述

我们知道每个进程是一个 task_struct 具体化的 PCB,以双向链表链接在一起,当需要运行进程时,CPU 会调用头指针,依次调度,如果有新的进程的话,就用尾指针加入到队列后面就行了

运行态R 指的不是正在运行,而是完全准备好了,可随时被调度器调度分配时间片给 CPU,每个时间片大概是 10ms,并不是一个进程全部运行完了才运行下一个,而是每个进程运行一点就被放下来,不断 进程切换,这样可以保证进程不会等待太久而被误杀,所有的进程会在一个时间段内被执行,叫做 并发执行

1.2 阻塞态S(浅度睡眠)

在这里插入图片描述

如图所示,对于设备来说在操作系统里也有一个队列链接起来,举个例子,当某个进程在等待键盘输入数据用于读取时,该进程会从原本的运行队列被链入到键盘的队列中,等待键盘该外部设备输入数据,该状态就叫做 阻塞态S

由于 CPU 的速度远远大于设备,因此捕捉运行中的状态很大概率都是 S 状态

1.3 阻塞态D(深度睡眠)

在这里插入图片描述

阻塞态其实有两种状态,假设有一个进程要往磁盘中写入 1GB 数据,此时写入到一半的过程中,磁盘的空间满了,该进程就有可能因为写入失败而被操作系统杀掉,数据代码等都没有了,万一这些数据很重要不就完犊子了吗?因此可以将进程设置为 深度睡眠的阻塞态D,相当于提示系统不能杀掉该进程,很重要!可以随时杀掉或唤醒的进程就是 浅度睡眠的阻塞态S

一般来说,出现一个 D 状态就说明该系统快崩溃了,有多个 D 状态进程说明这个系统基本已经崩溃了

1.4 挂起态T

在这里插入图片描述

系统中的进程只要处于闲置状态,一般都可以属于挂起状态,就拿阻塞态来说,当操作系统的内存资源严重不足的时候,就需要调整资源,会将一些不那么重要的进程,保留其 PCB,数据代码放到磁盘的 swap 区保存,此时就处于 挂起状态,当需要的时候再把数据交换回去就好了,T 状态出现的时间很短,一般很难捕捉到

1.5 挂起态t(追踪)

当进程被调试器(如 gdb)追踪时,会显示为小写 t 状态。此时进程因调试需求被暂停,等待调试指令(如断点处)

1.6 终止态X

X 状态的全称是 TASK_DEAD,表示进程已经完成执行,正处于退出清理阶段。当一个进程终止(无论是正常退出、被信号终止还是崩溃),内核会:

  • 回收进程占用的资源(如内存、文件描述符)
  • 更新进程表信息(如设置退出码)
  • 最终将进程标记为 X 状态,等待父进程通过 wait() 系列系统调用 “回收”(即清理进程表项)

这个状态只是一个返回状态,你不会在任务列表里看到这个状态

1.7 僵尸态Z(僵尸进程)

在这里插入图片描述

其实在 终止态X 之前还存在一个父子关系的状态:僵尸态Z,我们将以如图代码为例子,理解僵尸进程

在这里插入图片描述

当子进程终止之后,原先的 S 状态就会变成 Z 状态,子进程的 PCB 释放大部分资源,但是仍然有一部分资源(如进程 ID、退出码、终止原因,尤其是 task_struct 结构体)需要父进程通过 wait()waitpid() 等系统调用回收子进程,获取其退出信息并彻底清除残留数据

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

1.8 孤儿进程

孤儿进程是指其父进程已经终止或退出,而自身仍在运行的子进程

正常情况下,子进程由父进程创建并管理,父进程会监控子进程的运行状态。但如果:

  • 父进程意外崩溃或被强制终止(如收到 SIGKILL 信号)
  • 父进程正常退出但未正确处理子进程

此时,仍在运行的子进程就会成为孤儿进程,因为到最后都是需要退出这个进程的,此时子进程的父进程会变成 1 号进程(操作系统),相当于被操作系统领养了,所以叫 孤儿进程

2.进程优先级

2.1 查看优先级

[zzh_test@hcss-ecs-6aa4 zombie]$ ps -al
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1002 32721 32562  0  80   0 -  1054 hrtime pts/0    00:00:00 zombie_test
1 Z  1002 32722 32721  0  80   0 -     0 do_exi pts/0    00:00:00 zombie_test <defunct>
0 R  1002 32746 32723  0  80   0 - 38332 -      pts/1    00:00:00 ps

利用 ps -al 命令查看,PRI 表示优先级,即进程的优先级,或者通俗点说就是程序被CPU 执行的先后顺序,此值越小,进程的优先级别越高,那 NI 呢?就是我们所要说的 nice 值了,其表示进程可被执行的优先级的修正数值,PRI 值越小越快被执行,那么加入 nice 值后,将会使得 PRI 变为:PRI(new)=PRI(old)+nice

这样,当 nice 值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行,所以,调整进程优先级,在 Linux 下,就是调整进程 nice 值,nice 其取值范围是 -2019,一共 40 个级别

2.2 修改优先级

修改优先级用 top 命令更改已存在进程的 nice

在这里插入图片描述

R 键进入修改 nice 值的模式,然后输入对应正在运行的进程的 PID

在这里插入图片描述

接着输入范围 -19~20nice 值进行修改

在这里插入图片描述

可以看到优先值确实被调整了,一般来说是不需要调整的,只有特定的情况需要调整

2.3 优先级调度本质

在这里插入图片描述

CPU 中有一个 runqueue 结构体,存有一个 waiting 哈希表(wait 指针指针指向该表)和一个 running 哈希表(run指针指针指向该表),由于进程太多了,实际上这个哈希表是个位图,按照特定的计算方式将进程放到比特位里,对于优先级的进程来说,进程 [60,99] 对应比特位 [100,139][0,99] 是别的种类的进程,每个进程 task_struct 按照优先级从上往下,从左到右挂在 running 哈希表,运行完之后就挂到 waiting 哈希表相应的优先级位置,在这过程中可能会有些新创建的进程或者等待的进程,那么将这些进程放在 waiting 哈希表即可,当 running 哈希表执行完之后,其被指向的 run 指针,和 waiting 哈希表的 wait 指针交换,就能调度另一个队列变成运行队列了,依次循环往复即可

🤔那么如何判断该队列已经调度完了?

由于我们这个是位图,只要遍历一遍,每个比特位上是 0 就能判断已经调度完了

3.其他概念

  • 竞争性: 系统进程数目众多,而 CPU 资源只有少量,甚至 1 个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
  • 并行: 多个进程在多个 CPU 下分别,同时进行运行,这称之为并行
  • 并发: 多个进程在一个 CPU 下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发
  • 上下文数据: 简单而言即为临时数据,进程切换时,部分上下文数据会被保存到寄存器方便下一次直接启动进程

希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

请添加图片描述

http://www.dtcms.com/a/337729.html

相关文章:

  • 遨游三防科普|三防平板是指哪三防?应用在什么场景?
  • linux对外提供snmp服务
  • Pytest项目_day18(读取ini文件)
  • Spring Boot 实用小技巧:多级缓存(Caffeine + Redis)- 第545篇
  • 如何解决机器翻译的“幻觉“问题(Hallucination)?
  • 当AI学会“思考”:大语言模型背后的智能本质与伦理边界
  • 【提示词技巧】通用提示词原则介绍
  • Linux学习-软件编程(进程间通信1)
  • ROS 2 中用于建图的一些 topic
  • PyTorch神经网络工具箱(优化器)
  • buuctf:护网杯_2018_gettingstart、oneshot_tjctf_2016
  • llamafactory使用qlora训练
  • VectorDB+FastGPT一站式构建:智能知识库与企业级对话系统实战
  • 使用LLaMA-Factory对大模型进行微调-详解
  • OSG+Qt —— 笔记2- Qt窗口绘制棋盘及模型周期运动(附源码)
  • linux:告别SSH断线烦恼,Screen命令核心使用指南
  • 第四章:大模型(LLM)】07.Prompt工程-(1)Prompt 原理与基本结构
  • 大数据分析-读取文本文件内容进行词云图展示
  • Zephyr 中的 bt_le_per_adv_set_data 函数的介绍和应用方法
  • [机器学习]09-基于四种近邻算法的鸢尾花数据集分类
  • 具身智能赋能轮椅机器人的认知革命与人机共生新范式
  • 【软考架构】第4章 信息安全的抗攻击技术
  • 从「行走」到「思考」:机器人进化之路与感知—决策链路的工程化实践
  • 微电网管控系统中python多线程缓存与SQLite多数据库文件连接池实践总结(含源码)
  • 安川YASKAWA焊接机器人保护气智能节气阀
  • 蓝牙 GFSK RX Core 架构解析
  • Linux下的软件编程——IPC机制
  • 重复(Repeat)和迭代(Iteration)区别、递归(Recursion)
  • 超级云平台:重构数字生态的“超级连接器“
  • 想找出版社出书?这样选就对了!