< 9 > Linux 进程:进程状态 + 进程切换 + 附带常用指令(jobs / fg / kill / ps)

[1. 进程状态](#1. 进程状态)

[1.1 操作系统科学 的 进程状态](#1.1 操作系统科学 的 进程状态)

[1.11 运行态 & 就绪态 ------ 就绪未出队,等待运行。运行已出队,正在运行](#1.11 运行态 & 就绪态 —— 就绪未出队,等待运行。运行已出队,正在运行)

[1.12 阻塞态 ------ 卡住 就去 卡住的软硬件 的 等待队列 等待资源](#1.12 阻塞态 —— 卡住 就去 卡住的软硬件 的 等待队列 等待资源)

[1.13 挂起态 ------ 与磁盘进行大量IO操作,以时间换空间,卡顿的原因](#1.13 挂起态 —— 与磁盘进行大量IO操作,以时间换空间,卡顿的原因)

[1.2 调度队列是啥? ------ Linux内核双链表的实现方式](#1.2 调度队列是啥? —— Linux内核双链表的实现方式)

[1.3 Linux内核 根据偏移量求地址的方式](#1.3 Linux内核 根据偏移量求地址的方式)

[1.4 这么麻烦,为了? ------ 链表节点 可改造成其他 数据结构,并且都具备通用性!](#1.4 这么麻烦,为了? —— 链表节点 可改造成其他 数据结构,并且都具备通用性!)

[1.5 Linux 操作系统 的 进程状态](#1.5 Linux 操作系统 的 进程状态)

[1.51 R(running)运行态 ------ 在调度队列中就是运行态](#1.51 R(running)运行态 —— 在调度队列中就是运行态)

[1.511 ps axj ------ 可观察进程属性。搭配grep行过滤关键词](#1.511 ps axj —— 可观察进程属性。搭配grep行过滤关键词)

[1.512 查看循环printf进程,总是S,极少R? ------ CPU快,屏幕慢,printf频繁在等待屏幕输出](#1.512 查看循环printf进程,总是S,极少R? —— CPU快,屏幕慢,printf频繁在等待屏幕输出)

[1.513 查看状态,总是有+或s ------ [ ]+是前台进程,[ ]是后台进程,s是登录shell会话首进程](#1.513 查看状态,总是有+或s —— [ ]+是前台进程,[ ]是后台进程,s是登录shell会话首进程)

[1.514 ./myproc & ------ 加 & 在结尾,就能在后台启动进程!无法ctrl + c杀死!](#1.514 ./myproc & —— 加 & 在结尾,就能在后台启动进程!无法ctrl + c杀死!)

[1.515 kill -9 [进程pid] ------ 杀死后台进程的方式](#1.515 kill -9 [进程pid] —— 杀死后台进程的方式)

[1.516 前台,后台? ------ 定义读取键盘的优先级是前台 + 多进程并行执行的效率提高](#1.516 前台,后台? —— 定义读取键盘的优先级是前台 + 多进程并行执行的效率提高)

[1.517 kill -l ------ 查看kill命令的全部选项中:9,18,19](#1.517 kill -l —— 查看kill命令的全部选项中:9,18,19)

[1.52 S(sleeping)可中断睡眠态 ------ 阻塞态,浅睡眠态(OS、指令随便杀)](#1.52 S(sleeping)可中断睡眠态 —— 阻塞态,浅睡眠态(OS、指令随便杀))

[1.53 T (stopped)停止态 ------ 抢前台资源,被OS强行休眠,阻塞态](#1.53 T (stopped)停止态 —— 抢前台资源,被OS强行休眠,阻塞态)

[1.530 jobs [-l] ------ 可查看后台进程的编号,pid,状态等](#1.530 jobs [-l] —— 可查看后台进程的编号,pid,状态等)

[1.530 fg [后台进程编号] ------ 将后台进程,拉回前台执行](#1.530 fg [后台进程编号] —— 将后台进程,拉回前台执行)

[1.531 kill -19 [pid] ------ stop,前台循环进程进入T,默认切换至后台进程](#1.531 kill -19 [pid] —— stop,前台循环进程进入T,默认切换至后台进程)

[1.532 kill -18 [pid] ------ 唤醒后台进程,会继续执行,但不会回到前台](#1.532 kill -18 [pid] —— 唤醒后台进程,会继续执行,但不会回到前台)

[1.54 t (tracing stop)追踪停止态 ------ 调试时,遇到断点,被调试器强行休眠](#1.54 t (tracing stop)追踪停止态 —— 调试时,遇到断点,被调试器强行休眠)

[1.541 cgdb是一个进程](#1.541 cgdb是一个进程)

[1.542 cgdb调试程序本质是打开了指定路径的可执行程序](#1.542 cgdb调试程序本质是打开了指定路径的可执行程序)

[1.543 调试器是父进程,运行的程序是子进程](#1.543 调试器是父进程,运行的程序是子进程)

[1.55 D(disk sleep)不可中断睡眠态 ------ 深睡眠态,阻塞态(无法杀,除了断电)](#1.55 D(disk sleep)不可中断睡眠态 —— 深睡眠态,阻塞态(无法杀,除了断电))

[1.56 Z(zombie)僵尸态 ------ 子进程结束,一定变成僵尸进程,等待父进程善后](#1.56 Z(zombie)僵尸态 —— 子进程结束,一定变成僵尸进程,等待父进程善后)

[1.561 孤儿进程 ------ 父进程先 Z,子进程都过继给systemd pid = 1:OS本身善后。孤儿进程默认被切换为后台进程](#1.561 孤儿进程 —— 父进程先 Z,子进程都过继给systemd pid = 1:OS本身善后。孤儿进程默认被切换为后台进程)

[1.57 X(dead)死亡态 ------ 由 Z 改为 X,是瞬时状态,无法查看](#1.57 X(dead)死亡态 —— 由 Z 改为 X,是瞬时状态,无法查看)

1. 进程状态

1.1 操作系统科学 的 进程状态

操作系统科学 的 进程状态 适用于 大部分操作系统

进程状态大类分3种:运行,阻塞,挂起

进程状态看起来遥不可及,实际上就是每个PCB中的整型变量 int state

只不过根据状态标记的不同,需要的操作,和导致的结果不同罢了。下面细说

1.11 运行态 & 就绪态 ------ 就绪未出队,等待运行。运行已出队,正在运行

就绪态:进程处在调度队列中,按照FIFO,等待分配CPU(还未出队)

运行态:进程从调度队列中,被调度选中、出队、正式占用CPU开始执行(已经出队)

1.12 阻塞态 ------ 卡住 就去 卡住的软硬件 的 等待队列 等待资源

阻塞态:进程 主动/被动 放弃 占用/等待 CPU,暂时不再参与调度,直到等待的资源获取成功,才会被唤醒

原理:进程处于运行态,正在占用CPU执行进程时,分两种情况阻塞态:

后台进程:强行读取抢占前台资源,如shell正在使用的键盘,被认为是插队,OS将其休眠,然后将该节点直接从 CPU 插入到 键盘硬件 的 等待队列 中,等待资源,进入阻塞态

前台进程:因为等待scanf读取键盘的输入资源,CPU调用库函数调用scanf,其封装了read()系统调用,CPU执行到系统调用发现没有读取到资源的输入,就会申请OS执行休眠函数,OS执行休眠函数,然后将该节点直接从CPU 插入 键盘硬件 的 等待队列 中,等待资源,进入阻塞态

1.13 挂起态 ------ 与磁盘进行大量IO操作,以时间换空间,卡顿的原因

挂起态:因为进程多且大,导致内存空间不足时,OS会将优先级较低的进程:就绪态、阻塞态 在内存中的代码段和数据段换入磁盘的swap分区空间,空留下PCB节点排队等待调度运行,这称为挂起状态。轮到他们运行时,会从磁盘拷贝回来,再运行。

细分:阻塞时挂起,是阻塞挂起态,就绪时挂起,是就绪挂起态

原理:

所有操作系统,一般 都会 给磁盘空间预留一段 swap分区

当内存空间不足时,OS为了提高空间,会将暂时运行不上的进程:就绪态、阻塞态的进程,将他们的在内存中 代码段 和 数据段 移动拷贝 到 磁盘的swap分区,扩大内存空间。PCB节点则不移动,就在原地等候排队调度。

缺陷:

磁盘的IO速度与CPU不是一个量级,速度差巨慢,这也是为什么进程越多,电脑/手机 越卡顿的原因:内存空间严重不足,需要与磁盘进行大量的IO操作来回切换数据,效率巨慢

1.2 调度队列是啥? ------ Linux内核双链表的实现方式

调度队列本质上是双链表,不过只是用了头尾插入删除操作

链表可以根据使用方式,改造成几乎任何常用的高级数据结构

Linux内核的链表,不是将每个PCB作为链表节点参数之一

而是:PCB内部内嵌链表节点,节点参数就两个:next,prev

为什么这么做? 原因:高度解耦、通用的泛型链表!

原思路链表:链表节点内嵌PCB,

缺陷:PCB参数改动,或者节点新增参数,所有链表节点立刻失效,都得跟着改!耦合度极高,不好维护

Linux内核链表思路:PCB内嵌链表节点

优点:PCB改变参数,都可通过链表节点,再通过求取偏移量的方式(后面),得到变量。

每个PCB都可以自定义变量,怎么样都能找到变量,而这又和链表无关:链表只负责链接和提供自己地址。耦合度极低,更好维护

1.3 Linux内核 根据偏移量求地址的方式

C/C++ : &a[0] 和 &a 的结果,在数字上,完全一致

都是数组的首地址。换作结构体:

&x &(x.a) 完全一样

都是结构体的首地址,得出地址后,根据结构体对齐原则,算出变量大小,加上偏移量,就能求出其他变量的地址!

基于此原理:假设0号地址存在结构体对象类型,直接强转(struct obj*)0,访问d元素,求偏移量:

既然offset是起始地址 - d的地址偏移量,那做个实验比较一下:

结论Linux内核中,可这样:

知道节点地址 -> (PCB*)0 -> 箭头访问节点 -> 取地址 -> 得出节点偏移量->反推真正PCB首地址

这样,PCB地址就得到了!想访问其他变量一样:直到变量名,重复上面过程!

1.4 这么麻烦,为了? ------ 链表节点 可改造成其他 数据结构,并且都具备通用性!

只需要改变链表的使用方式,就能以一个链表节点结构体,创建出几乎所有常用高级数据结构!并且也与链表节点本身一样,具备极强通用性!所有数据结构的源码就2行:

listnode* next ,listnode* prev!

1.5 Linux 操作系统 的 进程状态

1.51 R(running)运行态 ------ 在调度队列中就是运行态

1.511 ps axj ------ 可观察进程属性。搭配grep行过滤关键词

运行态:在调度队列中,就是运行态 ,这点 与 操作系统科学 的 概念不同。

严格来讲,需要区分 就绪态 和 运行态。

1.512 查看循环printf进程,总是S,极少R? ------ CPU快,屏幕慢,printf频繁在等待屏幕输出

利用ps axj 命令,观察进程运行的状态:

为啥一会是S(sleeping,浅睡眠态,阻塞态),一会又是R(running,运行态)?

按理来说,应该是一直在运行态?

原因:进程看似一直在运行,实则是屏幕设备的 IO速度太慢!

CPU跑代码飞快,但终端屏幕设备 IO 极慢,进程绝大部分时候都在等屏幕设备刷新!

所以就大部分时候都在浅睡眠的阻塞态

运气好,疯狂ps,可能发现它在R状态!但绝对是S状态更多

1.513 查看状态,总是有+或s ------ [ ]+是前台进程,[ ]是后台进程,s是登录shell会话首进程

正常启动启动进程,就是前台进程,状态总是带 +

前台进程,占据了前台资源,bash指令无法使用!

下面演示,后台进程如何运行:

1.514 ./myproc & ------ 加 & 在结尾,就能在后台启动进程!无法ctrl + c杀死!
1.515 kill -9 [进程pid] ------ 杀死后台进程的方式

杀死了。

1.516 前台,后台? ------ 定义读取键盘的优先级是前台 + 多进程并行执行的效率提高

多个进程,需要执行,如果都需要读取键盘文件,键盘只能由一个进程使用。

那肯定要按先后顺序提供读取

所以:先读取的,定义为前台进程。后读取的,称为后台进程。

前台进程只有一个,后台进程可以有很多个。因为目前都用不到键盘文件

效率提高:

不需要键盘的进程,统一在后台跑,前台只处理需要键盘的:如shell指令

这样:多进程同时执行,效率提升飞快!

如果只有前台:

输完指令,还得单独启动输出信息、磁盘IO文件等进程,效率低。

前台,后台:

不需要键盘的一律在后台执行!如果100个不需要,就节省100个操作运行时间!

1.517 kill -l ------ 查看kill命令的全部选项中:9,18,19

重点学习 9,18,19:杀死,继续,停止

SIG:kill CONT:continue STOP:stop

复制代码
效果等价
kill -9 PID
kill -SIGKILL PID 

1.52 S(sleeping)可中断睡眠态 ------ 阻塞态,浅睡眠态(OS、指令随便杀)

可中断睡眠态:主动 向OS申请休眠,从CPU离开 或 从调度队列出队,入队具体硬件的等待队列。本质是阻塞态

可中断:内存严重不足,OS可随便杀死进程,kill指令、crtl + c 也能随便杀进程

1.53 T (stopped)停止态 ------ 抢前台资源,被OS强行休眠,阻塞态

停止态:被动 休眠,因为抢占前台进程资源,被OS强行休眠,从就绪态,变为停止态:

PCB结构体节点被OS从调度队列出队,入队具体硬件的等待队列。本质也是阻塞态

1.530 jobs [-l] ------ 可查看后台进程的编号,pid,状态等
1.530 fg [后台进程编号] ------ 将后台进程,拉回前台执行
1.531 kill -19 [pid] ------ stop,前台循环进程进入T,默认切换至后台进程

前台如果在跑循环打印进程,kill -19 [pid] : 强制该进程T状态

因为前台不允许阻塞态,bash会自动取得操作权,把该进程由前台转移至后台

1.532 kill -18 [pid] ------ 唤醒后台进程,会继续执行,但不会回到前台

1.54 t (tracing stop)追踪停止态 ------ 调试时,遇到断点,被调试器强行休眠

追踪停止态:被动停止。debug版本exe,用调试器打断点调试时,运行到断点,进程就会被调试器强行休眠暂停,是阻塞态

1.541 cgdb是一个进程
1.542 cgdb调试程序本质是打开了指定路径的可执行程序

先区分:

cgdb:封装gdb,套的外壳

gdb --nw ... :真正的调试器,cgdb封装gdb整的可视化调试界面

1.543 调试器是父进程,运行的程序是子进程

如图:

cgdb是父进程,gdb是cgbd的子进程,同时是myproc的父进程!

1.55 D(disk sleep)不可中断睡眠态 ------ 深睡眠态,阻塞态(无法杀,除了断电)

不可中断睡眠态:与磁盘进行大量 IO 操作,可能涉及重要内容的交互,或者说为了保护读写安全,CPU执行时会申请OS标记为D:不允许被任何形式杀死,也不允许被swap挂起。断电能杀死。

允许从CPU离开、插入 IO 等待队列

一般情况都是S状态。极少情况是D状态

除非:与磁盘进行大量 IO 操作,磁盘老旧,读写故障率高,读写慢

涉及底层硬件的写入..

1.56 Z(zombie)僵尸态 ------ 子进程结束,一定变成僵尸进程,等待父进程善后

僵尸态:子进程结束后,它的代码段与数据段会立刻销毁。PCB不会彻底销毁:它会保留极少数状态信息如pid,state,子进程结束退出时,触发系统调用exit(),OS修改 state 为 Z。

此时就是僵尸状态:已经退出,但还没人读取的状态。

PCB在等父进程来读取。如果父进程早死了,无法读取,就会内存泄漏,变成孤儿进程!

为了解决内存泄漏,所有孤儿进程都会被过继给pid = 1 的OS内核大管家:systemd

如图:前台的僵尸进程!并且:会被标记 <defunct> 失效的,无用的!

1.561 孤儿进程 ------ 父进程先 Z,子进程都过继给systemd pid = 1:OS本身善后。孤儿进程默认被切换为后台进程

孤儿进程默认被切换为后台进程

1.57 X(dead)死亡态 ------ 由 Z 改为 X,是瞬时状态,无法查看

死亡态:子进程由 僵尸态 被 父进程 通过 系统调用wait(),被 OS 回收,标记为X,此时进程才算彻底结束,PCB才会被彻底销毁

相关推荐
枕星而眠1 小时前
一篇吃透 C++ 核心基础:初始化、引用、指针、内联、重载、右值引用
开发语言·数据结构·c++·后端·visual studio
openKylin1 小时前
紧急安全通告|Linux内核Dirty Frag漏洞(CVE-2026-43284、CVE-2026-43500)
linux·安全·web安全
无忧.芙桃1 小时前
硬核拆解:Linux动态库从原理到实战
linux·运维·服务器
小明同学011 小时前
计算机网络编程---系统调用到并发模型
linux·c++·计算机网络
LinuxGeek10241 小时前
CVE-2026-31431 - Linux Copy-Fail 漏洞利用 (Rust版本)和检测方案
linux·运维·服务器
xinhuanjieyi1 小时前
vscode插件,.sec / .inc / .sc 文件添加关键字高亮
java·服务器·vscode
cong_1 小时前
狐蒂云🦊跑路我的摸鱼岛没了!
前端·后端·github
learning-striving1 小时前
centos9安装docker测试成功教程
linux·运维·服务器·docker·容器
Data_Journal1 小时前
Puppeteer指纹识别指南:循序渐进,简单易学!
服务器·前端·人工智能·物联网·媒体