Linux中《进程状态--进程调度--进程切换》详细介绍

news2025/4/24 17:22:43

目录

  • 进程状态
    • Linux内核源代码怎么说
    • 运行&&阻塞&&挂起
    • 内核链表
  • 进程状态查看
    • Z(zombie)-僵尸进程
    • 僵尸进程危害
    • 孤儿进程
  • 进程优先级
  • 进程切换
  • Linux2.6内核进程O(1)调度队列

进程状态

Linux内核源代码怎么说

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

进程状态就是task_struct内的一个整形变量,也是一个标记位(宏定义的)。
状态决定了当前系统如何处理这个进程。
在这里插入图片描述

运行&&阻塞&&挂起

运行状态

该进程在调度队列中或者正在被CPU执行。

阻塞状态

等待某种设备或资源就绪(如果不就绪,我的进程就不会被调度)。
在这里插入图片描述
运行状态转化为阻塞状态,本质上就是把PCB链入到不同的数据结构当中!

只有在运行队列中,进程才会被调度,但是现在进程在设备队列中,那么如何再被CPU调度呢?
在这里插入图片描述
总结:进程状态变化的表现之一,就是CPB要在不同的数据结构之间进行流动,本质都是数据结构的增删查改。

挂起状态

当内存资源不足时,将wait_queue里的进程的代码和数据唤出到磁盘当中swap交换分区。如果次数键盘就绪了,OS会把磁盘当中该PCB的代码和数据再重新加载到内存,构建指针映射,这个也叫做唤入。我们把这个称为阻塞挂起,运行挂起也是同样的道理。
在这里插入图片描述

内核链表

在这里插入图片描述

下⾯的状态在kernel源代码⾥定义:

/*
*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 */ //暂停(追踪状态),例如debug的调试状态下,设置断点,进程被站暂停了
"X (dead)", /*16 */ //死亡
"Z (zombie)", /*32 */ //僵尸 ->为了获取退出信息

};

R运⾏状态(running): 并不意味着进程⼀定在运⾏中,它表明进程要么是在运⾏中要么在运⾏队列⾥
在这里插入图片描述
S睡眠状态(sleeping): 意味着进程在等待事件完成(这⾥的睡眠有时候也叫做可中断睡眠,浅睡眠。ctrl+c是可以杀掉这个进程的。
(interruptible sleep)(浅睡眠))。
在这里插入图片描述
D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),深度睡眠,在这个状态的进程通常会等待IO的结束,不可中断睡眠状态的进程不能被杀掉,只能等待它自己被唤醒,这样可以防止数据的丢失。例如:当进程往磁盘里写入内容时,此时如果内存资源严重不足时,需要杀掉进程时,该进程处于S状态,可以被杀掉,等待磁盘写入完数据,如果杀掉该进程,那么这个内容到底是写完了?还是没写完?我都不知道,磁盘也不知道该如何处理这一段内容,所以可能会存在数据丢失,此时,把该进程的状态修改为D,此时该进程不对任何杀掉的动作进行响应,OS就不会杀掉它。

T停⽌状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停⽌(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运⾏,如果进行非法操作,系统可以暂停进程,止损。

在这里插入图片描述

t (tracing stop): 暂停(追踪状态),例如debug的调试状态下,设置断点,进程被暂停了。

在这里插入图片描述

X死亡状态(dead):这个状态只是⼀个返回状态,你不会在任务列表⾥看到这个状态。

插播一个关于内核结构申请的小的知识点:要把释放的PCB回收时,可以用unuse链表把要回收的PCB节点链接起来,等创建新进程时,需要创建PCB节点时,把unuse链表里的PCB拿来用,这种技术叫做slab。数据结构对象的缓存,可以加速创建和释放进程的速度。

进程状态查看

ps aux / ps axj

  • a:显⽰⼀个终端所有的进程,包括其他⽤⼾的进程。
  • x:显⽰没有控制终端的进程,例如后台运⾏的守护进程。
  • j:显⽰进程归属的进程组ID、会话ID、⽗进程ID,以及与作业控制相关的信息
  • u:以⽤⼾为中⼼的格式显⽰进程信息,提供进程的详细信息,如⽤⼾、CPU和内存使⽤情况等

Z(zombie)-僵尸进程

  • 僵死状态(Zombies)是⼀个⽐较特殊的状态。当进程退出,进程的代码和数据被释放,但是PCB不会被释放,此时父进程还没有从子进程的PCB里获取退出信息。
  • 僵死进程会以终⽌状态保持在进程表中,并且会⼀直在等待⽗进程读取退出状态代码。
  • 所以,只要⼦进程退出,⽗进程还在运⾏,但⽗进程没有读取⼦进程状态,⼦进程进⼊Z状态。
  • 如果父进程一直不管,不回收,不获取子进程的退出信息,那么Z(僵尸状态)会一直存在,此时,会造成内存泄漏!!!
    在这里插入图片描述

僵尸进程危害

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

孤儿进程

  • ⽗进程如果提前退出,那么⼦进程后退出,进⼊Z之后,那该如何处理呢?
  • ⽗进程先退出,⼦进程就称之为“孤⼉进程”
  • 孤⼉进程被1号init进程领养,当然要有init进程回收喽。1号init进程我们可以理解为操作系统。
    在这里插入图片描述

有1号进程,那么有0号进程吗

有的,只不过刚开机时,被1号进程给替换掉了。

为什么要领养

为了回答这个问题,我们就要想一想,如果不领养会怎么样?子进程退出后,进入僵尸状态,如果没有父进程回收子继承,那么会造成内存泄漏。hou

注意:变成孤儿进程之后,被1号进程领养,子进程会自动变成后台进程,使用ctrl+c杀不掉它的,但是后台进程可以向前台进程打印信息。

进程优先级

基本概念

  • cpu资源分配的先后顺序,就是指进程的优先权(priority)
  • 优先权⾼的进程有优先执⾏权利。配置进程优先权对多任务环境的linux很有⽤,可以改善系统性能。
  • 还可以把进程运⾏到指定的CPU上,这样⼀来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
    总结:进程优先级就是进程得到资源的先后顺序。

为什么会有优先级这个概念?
CPU太少了,内存太少了,进程又多,目标资源稀缺,导致需要通过优先级来确认谁先谁后的问题。

优先级VS权限

优先级:能得到这个资源,只不过是先后的问题。
权限:能不能得到这个资源。
查看系统进程
在linux或者unix系统中,⽤ps ‒l命令则会类似输出以下⼏个内容:
在这里插入图片描述

我们很容易注意到其中的⼏个重要信息,有下:

• UID : 代表执⾏者的⾝份,user id。
在这里插入图片描述
Linux系统中,访问任何资源,都是进程代表用户去访问的。进程当中的UID代表的是该进程是被哪个用户启动的。OS中用户名字是给我们看的,系统里面区分用户是用的UID,当进程去访问文件的时候,OS会把进程的UID和文件的用户的权限进行对比,查看该进程是否有权限。

• PID : 代表这个进程的代号
• PPID :代表这个进程是由哪个进程发展衍⽣⽽来的,亦即⽗进程的代号
• PRI :代表这个进程可被执⾏的优先级,其值越⼩越早被执⾏,默认是80
• NI :代表这个进程的nice值,进进程优先级的修正数据,默认值为0
进程真实的优先级 = PRI(默认) + NI

修改进程优先级

1.top->r->pid
在这里插入图片描述

2.使用 nice 命令
nice 命令用于在启动新进程时设置其优先级。其语法为:
nice -n <nice_value> <command>

3.使用 renice 命令
renice 命令用于调整已经运行中的进程的优先级。其语法为:
renice <nice_value> -p <pid>

4使用 setpriority() 系统调用

#include <sys/time.h>
#include <sys/resource.h>
int setpriority(int which, id_t who, int value);
参数:
which:指定要调整优先级的对象类型,可以是 PRIO_PROCESS(进程)、PRIO_PGRP(进程组)或 PRIO_USER(用户)。
who:指定要调整优先级的对象 ID。如果 which 是 PRIO_PROCESS,则 who 是进程 ID;如果是 PRIO_PGRP,则 who 是进程组 ID;如果是 PRIO_USER,则 who 是用户 ID。
value:新的 nice 值,范围是 -20 到 19。

PRI and NI

• PRI也还是⽐较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执⾏的先后顺序,此值越⼩进程的优先级别越⾼。
• 那NI呢?就是我们所要说的nice值了,其表⽰进程可被执⾏的优先级的修正数值。
• PRI值越⼩越快被执⾏,那么加⼊nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
• 这样,当nice值为负值的时候,那么该程序将会优先级值将变⼩,即其优先级会变⾼,则其越快被执⾏。
• 所以,调整进程优先级,在Linux下,就是调整进程nice值。

PRI vs NI

需要强调⼀点的是,进程的nice值不是进程的优先级,他们不是⼀个概念,但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据。

优先级的极值问题

nice的范围是[-20,19],也就是说,PRI的范围是[60,99],幅度为40。考虑到公平性,幅度不能太大,优先级设立的不合理,会导致优先级低的进程,长时间得不到CPU的资源,进而导致进程饥饿。

查看进程优先级的命令
⽤top命令更改已存在进程的nice值:

• top
• 进⼊top后按“r”‒>输⼊进程PID‒>输⼊nice值

注意:
其他调整优先级的命令:nicerenice

进程切换

CPU上下⽂切换:其实际含义是任务切换, 或者CPU寄存器切换。当多任务内核决定运⾏另外的任务时, 它保存正在运⾏任务的当前状态, 也就是CPU寄存器中的全部内容。这些内容被保存在任务⾃⼰的堆栈中, ⼊栈⼯作完成后就把下⼀个将要运⾏的任务的当前状况从该任务的栈中重新装⼊CPU寄存器,并开始下⼀个任务的运⾏, 这⼀过程就是context switch
在这里插入图片描述
结论:

  • 寄存器:保存正在运行的进程的临时数据,是CPU内部保存数据的临时空间。
  • 寄存器 != 寄存器里的数据。寄存器是一段空间,只有1份,寄存器里的数据,是内容,变化的,可以有多份。
  • 进程切换最核心的,就是保存和恢复当前进程的硬件上下文数据,即CPU内寄存器的内容。
  • 当前进程把自己的硬件上下文数据保存到了task_struct里,在结构体里可以命名一些寄存器的变量,来存放相关数据,当进程被切换时,找到task_struct里的数据,把数据放到CPU里的寄存器里。由于task_struct的内容很多,所以当代OS把硬件上下文数据独立保存了TSS里,没有放在task_struct里了,但是task_struct存放了TSS的地址。

在这里插入图片描述

  • 如何区分全新的进程和已经被调度过的进程?可以使用标记位(int isrunning),如果是新进程,isrunning的值为0,如果被调度过,isrunning为1.
  • 时间⽚:当代计算机都是分时操作系统,每一个进程都有它合适的时间⽚(其实就是⼀个计数器)。时间⽚到达,进程就被操作系统从CPU中剥离下来。

Linux2.6内核进程O(1)调度队列

背景知识:

调度器:是由调度和切换共同构成的,调度和切换也是两个不同的动作。
分时操作系统VS实时操作系统

分时操作系统是基于时间片的操作系统,时间片一结束,进程就会从CPU上剥离下来。
实时操作系统是一个进程运行完,才运行下一个进程,工业领域运行较多。
在这里插入图片描述

上图是Linux2.6内核中进程队列的数据结构。

⼀个CPU拥有⼀个runqueue

如果有多个CPU就要考虑进程个数的负载均衡问题

优先级

普通优先级:100〜139(我们都是普通的优先级,想想nice值的取值范围,可与之对应!)
实时优先级:0〜99(不关⼼)

活动队列

• 时间⽚还没有结束的所有进程都按照优先级放在该队列
• nr_active: 总共有多少个运⾏状态的进程
• queue[140]: ⼀个元素就是⼀个进程队列,相同优先级的进程按照FIFO规则进⾏排队调度,所以,数组下标就是优先级!
• 从该结构中,选择⼀个最合适的进程,过程是怎么的呢?
1. 从0下表开始遍历queue[140]
2. 找到第⼀个⾮空队列,该队列必定为优先级最⾼的队列
3. 拿到选中队列的第⼀个进程,开始运⾏,调度完成!
4. 遍历queue[140]时间复杂度是常数!但还是太低效了!
• bitmap[5]:⼀共140个优先级,⼀共140个进程队列,为了提⾼查找⾮空队列的效率,就可以⽤5*32个⽐特位表⽰队列是否为空,这样,便可以⼤ 提⾼查找效率!
在这里插入图片描述

过期队列

  • 过期队列和活动队列结构⼀模⼀样
  • 过期队列和活动队列结构一模一样
  • 过期队列上放置的进程,都是时间⽚耗尽的进程
  • 当活动队列上的进程都被处理完毕之后,对过期队列的进程进⾏时间⽚重新计算

active指针和expired指针

• active指针永远指向活动队列
• expired指针永远指向过期队列
• 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间⽚到期时⼀直都存在的。
• 没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了⼀批新的活动进程

为什么优先级既有PRI,又有NI?
如果在活跃队列里,把一个进程的优先级由80到60,我们是把该进程的位置调整吗?还是调整过期队列里的位置呢?这样做都不是很好,利用NI,活跃进程里的进程调度完之后,在过期队列里,根据NI,再重新调整该进程的位置。

总结

• 在系统当中查找⼀个最合适调度的进程的时间复杂度是⼀个常数,不随着进程增多⽽导致时间成本增加,我们称之为进程调度O(1)算法!

在这里插入图片描述

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

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

相关文章

蓝桥杯备考:多米诺骨牌

这道题要求上下方格子和之差要最小&#xff0c;其实就是算每个上下格子的差求和的最小值 这道题其实是动态规划01背包问题 我们直接按步骤做吧 step1:定义状态表示f[i][j]表示从1到i个编号的差值里选出刚好j个数的最小操作次数 step2:推导状态转移方程 如图这就是我们的状态…

AudioFlinger与AudioPoliceManager初始化流程

AF/APF启动流程 在启动AudioSeriver服务的过程中会对启动AF/APF。main_audioserver.cpp有如下代码&#xff1a; AudioFlinger::instantiate();AudioPolicyService::instantiate();AF初始化流程 1.AudioFlinger::instantiate() 1.1 AudioFlinger构造函数 void AudioFlinger:…

网路传输层UDP/TCP

一、端口号 1.端口号 1.1 五元组 端口号(port)标识了一个主机上进行通信的不同的应用程序. 如图所示, 在一个机器上运行着许多进程, 每个进程使用的应用层协议都不一样, 比如FTP, SSH, SMTP, HTTP等. 当主机接收到一个报文中, 网络层一定封装了一个目的ip标识我这台主机, …

Python大数据处理 基本的编程方法

目录 一、实验目的 二、实验要求 三、实验代码 四、实验结果 五、实验体会 一、实验目的 体会基本的python编程方法&#xff1b;学习python中的各类函数&#xff1b;了解python读取与写入文件的方法。 二、实验要求 输入2000年后的某年某月某日&#xff0c;判断这一天是…

STM32F103_LL库+寄存器学习笔记06 - 梳理串口与串行发送“Hello,World“

导言 USART是嵌入式非常重要的通讯方式&#xff0c;它的功能强大、灵活性高且用途广泛。只停留在HAL库层面上用USART只能算是入门&#xff0c;要加深对USART的理解&#xff0c;必须从寄存器层面入手。接下来&#xff0c;先从最简单的USART串行发送开始。 另外&#xff0c;在接…

硬件基础--14_电功率

电功率 电功率:指电流在单位时间内做的功(表示用电器消耗电能快慢的一个物理量)。 单位:瓦特(W)&#xff0c;简称瓦。 公式:PUI(U为电压&#xff0c;单位为V&#xff0c;i为电流&#xff0c;单位为A&#xff0c;P为电功率&#xff0c;单位为W)。 单位换算:进位为1000&#xff…

Vue.js 完全指南:从入门到精通

1. Vue.js 简介 1.1 什么是 Vue.js? Vue.js(通常简称为 Vue)是一个用于构建用户界面的渐进式 JavaScript 框架。所谓"渐进式",意味着 Vue 的设计是由浅入深的,你可以根据自己的需求选择使用它的一部分或全部功能。 Vue 最初由尤雨溪(Evan You)在 2014 年创…

在Git仓库的Readme上增加目录页

一般在编写Readme时想要增加像文章那样的目录&#xff0c;方便快速跳转&#xff0c;但是Markdown语法并没有提供这样的方法&#xff0c;但是可以通过超链接结合锚点的方式来实现&#xff0c;如下图是我之前一个项目里写的Readme&#xff1a; 例如有下面几个Readme内容&#xff…

C# SolidWorks 二次开发 -各种菜单命令增加方式

今天给大家讲一讲solidworks中各种菜单界面&#xff0c;如下图&#xff0c;大概有13处&#xff0c;也许还不完整哈。 1.CommandManager选项卡2.下拉选项卡3.菜单栏4.下级菜单5.浮动工具栏6.快捷方式工具栏7.FeatureManager工具栏区域8.MontionManager区域 ModelView?9.任务窗…

【RocketMQRocketMQ Dashbord】Springboot整合RocketMQ

【RocketMQ&&RocketMQ Dashbord】Springboot整合RocketMQ 【一】Mac安装RocketMQ和RocketMQ Dashbord【1】安装RocketMQ&#xff08;1&#xff09;下载&#xff08;2&#xff09;修改 JVM 参数&#xff08;3&#xff09;启动测试&#xff08;4&#xff09;关闭测试&…

《白帽子讲 Web 安全》之跨站请求伪造

引言 在数字化时代&#xff0c;网络已深度融入人们生活的方方面面&#xff0c;Web 应用如雨后春笋般蓬勃发展&#xff0c;为人们提供着便捷高效的服务。然而&#xff0c;繁荣的背后却潜藏着诸多安全隐患&#xff0c;跨站请求伪造&#xff08;CSRF&#xff09;便是其中极为隐蔽…

K8S学习之基础五十:k8s中pod时区问题并通过kibana查看日志

k8s中pod默认时区不是中国的&#xff0c;挂载一个时区可以解决 vi pod.yaml apiVersion: v1 kind: Pod metadata:name: counter spec:containers:- name: countimage: 172.16.80.140/busybox/busybox:latestimagePullPolicy: IfNotPresentargs: [/bin/sh,-c,i0;while true;do …

nginx代理前端请求

一&#xff0c;项目配置 我在 ip 为 192.168.31.177 的机器上使用 vue3 开发前端项目&#xff0c;项目中使用 axios 调用后端接口。 这是 axios 的配置&#xff1a; import axios from axios;const request axios.create({baseURL: http://192.168.31.177:8001,// 设置请求…

Android生态大变革,谷歌调整开源政策,核心开发不再公开

“开源”这个词曾经是Android的护城河&#xff0c;如今却成了谷歌的烫手山芋。最近谷歌宣布调整Android的开源政策&#xff0c;核心开发将全面转向私有分支。翻译成人话就是&#xff1a;以后Android的核心更新&#xff0c;不再公开共享了。 这操作不就是开源变节吗&#xff0c;…

银行分布式新核心的部署架构(两地三中心)

银行的核心系统对可用性和性能要求均非常严苛&#xff0c;所以一般都采用两地三中心部署模式。 其中&#xff1a; 同城两个主数据中心各自部署一套热备&#xff0c;平时两个中心同时在线提供服务&#xff0c;进行负载均衡假如其中一个数据中心出现异常&#xff0c;则由另外一个…

MantisBT在Windows10上安装部署详细步骤

MantisBT 是一款基于 Web 的开源缺陷跟踪系统&#xff0c;以下是在 Windows 10 上安装部署 MantisBT 的详细步骤&#xff1a; 1. 安装必要的环境 MantisBT 是一个基于 PHP 的 Web 应用程序&#xff0c;因此需要安装 Web 服务器&#xff08;如 Apache&#xff09;、PHP 和数据…

9.4分漏洞!Next.js Middleware鉴权绕过漏洞安全风险通告

今日&#xff0c;亚信安全CERT监控到安全社区研究人员发布安全通告&#xff0c;Next.js 存在一个授权绕过漏洞&#xff0c;编号为 CVE-2025-29927。攻击者可能通过发送精心构造的 x-middleware-subrequest 请求头绕过中间件安全控制&#xff0c;从而在未授权的情况下访问受保护…

OpenCV图像拼接(5)图像拼接模块的用于创建权重图函数createWeightMap()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::createWeightMap 是 OpenCV 库中用于图像拼接模块的一个函数&#xff0c;主要用于创建权重图。这个权重图在图像拼接过程中扮演着重…

CTF类题目复现总结-[MRCTF2020]ezmisc 1

一、题目地址 https://buuoj.cn/challenges#[MRCTF2020]ezmisc二、复现步骤 1、下载附件&#xff0c;得到一张图片&#xff1b; 2、利用010 Editor打开图片&#xff0c;提示CRC值校验错误&#xff0c;flag.png应该是宽和高被修改了&#xff0c;导致flag被隐藏掉&#xff1b;…

linux打包前端vue,后端springboot项目

第一步先对整个项目进行通过maven进行clean在进行compile 第二步直接进行打包package和install都可以 第三部把对应的jar放到服务器上 把jar包放到服务器上某个地址下&#xff0c;然后cd到这个目录下&#xff0c;然后执行命令 nohup java -jar ruoyi-admin.jar > springbo…