【Linux进程】进程状态(运行&&阻塞&&挂起)

目录

前言

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

[2. 运行状态](#2. 运行状态)

[3. 阻塞状态](#3. 阻塞状态)

[4. 挂起状态](#4. 挂起状态)

[5. Linux中具体的状态](#5. Linux中具体的状态)

总结


前言

在Linux操作系统中,进程状态非常重要,它可以帮助我们了解进程在系统中的运行情况,从而更好地管理和优化系统资源,在Linux系统中,进程可以处于不同的状态,本文我们来聊一聊运行、阻塞、挂起这几状态;

1. 进程状态

在许多教材以及资料当中有许多对进程状态的总结与描述,资料不同它们的描述也各有略同,但总都是一些概念,Linux进程状态具体是什么?本文我们将从底层出发,聊一聊运行、阻塞、挂起这几状态;

温馨提示:如果在本文中某些名称或者内容不太了解,可以先阅读这篇文章:

Linux进程的理解

2. 运行状态

从计算机硬件出发,我们写的代码生成可执行文件都被存储在磁盘当中,想要让程序运行就必须将程序加载到内存当中;

每一个程序(进程)都会有一个属于自己的PCB,通过PCB来进行排队,等待CPU的调度;

为了便于调度管理,操作系统会在内存当中维护一个叫运行队列的结构,所有就绪状态的进程的PCB会被加入到这个队列当中;

CPU在调度执行时就会通过这个运行队列拿到进程的PCB,进而调度执行该进程;

只要进程在这个运行队列当中,它的状态就是运行状态;每个CPU在系统中都会维护一个运行队列;

3. 阻塞状态

了解完运行状态,我们再来聊一聊阻塞状态,阻塞状态是建立在进程被调度执行的基础上;

在CPU执行一个进程时,都可能会或多或少的去访问系统的某些资源,比如:我们使用的scanf,在执行时需要调用键盘(本质就是从键盘中读取数据);

我们不输入,键盘的数据就是没有就绪(进程需要访问的数据没有就绪),此时进程无法继续执行,需要等待数据;

状态又是如何转变的呢?

操作系统和驱动程序它们对硬件进行管理,每个硬件都会有一个属于自己的结构描述,通过指针链接,操作系统通过链表(dev_list)达到对硬件设施的管理;

当进程正在等待某个硬件的资源时,把进程的PCB加入到硬件设备结构描述的等待队列当中,并把PBC的状态设置为阻塞状态;当PCB在这个等待队列中等待数据资源时,这个状态就叫做阻塞状态;

系统资源等待结束之后,操作系统会再次将等待队列中的PCB移入到运行队列当中,并把状态修改为运行状态,等待CPU的执行调度;

4. 挂起状态

了解完阻塞状态,我们来聊一聊挂起状态;挂起全称:阻塞挂起;

挂起是基于阻塞的一种状态;

进程处于阻塞状态时,并且内存不足的情况下就会出现;

针对于这种情况,操作系统会将阻塞进程的代码和数据置换到外设,此时该进程的状态就被称为挂起状态;

阻塞进程的代码和数据一般会存放在磁盘的swap分区,当进程被操作系统调度时,被置换到外设的代码和数据又会重新加载到内存;

拓展补充

一般情况下,swap分区的大小不会太大,大概等于内存的大小,过大的swap分区会导致操作系统过于依赖swap分区,导致效率变低;

5. Linux中具体的状态

说了这么多理论,那么在Linux中进程的状态又是怎样的?

cpp 复制代码
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内核源码对进程状态的定义;它其实并没有像阻塞挂起这样的状态;

我们也可以写一个程序来测试一下:

cpp 复制代码
#include <stdio.h>
#include <unistd.h>

int main()
{
    while(1)
    { 
        printf("hello world! \n");
    }
    return 0;
}

在Linux环境下编译运行,然后使用监控进行观察:

bash 复制代码
while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep; sleep 1; done
//myprocess是可执行文件的名称

观察到的情况分为两种,大多数是S+,极少数是R+:

主要是因为调用的printf,在输出时需要调用显示器,大多数的时间都是在等待显示器;我们也可以写一个空的死循环执行来观察;

R状态我们都知道是运行状态,S状态是什么?

S(sleeping)休眠状态,这里的睡眠是浅度睡眠,可以对发送的信号做出响应;

这里的 "+" 号是什么意思?

进程被分为前台进程和后台进程,带+号就表示是前台进程;

  • 前台进程:正常使用 ./可执行程序,这种执行方式运行起来就是前台进程,前台进程运行时,无论我们怎么输入指令都无法被执行(Ctrl +c可终止进程)
  • 后台进程:./ 可执行程序 & 这种执行方式运行起来就是后台进程,后台进程运行时,我们输入的指令依然可以执行(Ctrl +c 无法终止进程,使用kill + 9 +进程pid 杀死进程)

这里的S状态其实就是上述阻塞状态;

D状态

D(disk sleep)也是休眠状态,它是深度休眠,专门针对磁盘设计的;

当进程需要将较大的数据写入到磁盘当中,在等待磁盘写入时进程的状态就是休眠状态;如果是S状态:

在内存严重不足的情况下,操作系统没办法时会通过杀死进程的方式来节省资源;如果在等待的过程中进程被操作系统杀掉,并且磁盘写入数据失败,那么就会导致数据无法再加载(数据丢失);为了避免这种情况,就可以把等待数据写入的进程状态设为D状态;

D状态无法被杀掉(OS也不行),只能等待执行完毕后状态转换;

注意:

如果用户看到了D状态,说明计算机几乎要挂掉了

T状态

T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行

bash 复制代码
kill -SIGSTOP  <进程ID>

使用kill指令可以查看发送给信号的所有类型:

bash 复制代码
kill -l

为什么要停止?

进程在访问资源时,可能暂时不允许进程访问,这时OS就会将进程的状态设置为stop(T状态)

t状态

t状态也是停止状态,Linux中没有进行区分;

主要出现在程序Debug时,在Debug的时候,遇到断点,进程就暂停,此时就是t状态

在上述的D状态、T状态、t状态其实都是阻塞状态,阻塞可以等待硬件资源也可以等待软件资源

比如:一个进程等待另一个进程,进程的PCB里可以有PCB* wait_queue,比如gdb的进程等待Debug的进程;

X状态

X状态(死亡状态),就是我们常说的终止状态,它是一个瞬时状态,不会在任务列表里看到这个状态

最后就是Z(zombie)僵尸状态,僵尸状态较为复杂,Linux系统中的僵尸进程状态也是一种特殊的进程状态,通常是指一个子进程已经结束运行,但其父进程还未对其进行善后处理(如调用wait()函数)。如果不及时清理僵尸进程,会导致系统资源泄漏,影响系统性能甚至造成系统崩溃;


总结

本文主要从底层出发向大家介绍了运行、阻塞、挂起这几种常见的状态,并且将Linux中具体的状态进行了一系列介绍,可以划分为这几种状态;最后是僵尸状态,僵尸状态的情况较为特殊,如果不及时处理也会造成比较严重的后果,我们下期再来进行详细的介绍,以上便是本文的全部内容,希望可以对你有所帮助,感谢阅读!

相关推荐
Abladol-aj1 小时前
并发和并行的基础知识
java·linux·windows
JunLan~5 小时前
Rocky Linux 系统安装/部署 Docker
linux·docker·容器
方竞6 小时前
Linux空口抓包方法
linux·空口抓包
sun0077007 小时前
ubuntu dpkg 删除安装包
运维·服务器·ubuntu
海岛日记7 小时前
centos一键卸载docker脚本
linux·docker·centos
AttackingLin8 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
吃肉不能购9 小时前
Label-studio-ml-backend 和YOLOV8 YOLO11自动化标注,目标检测,实例分割,图像分类,关键点估计,视频跟踪
运维·yolo·自动化
学Linux的语莫9 小时前
Ansible使用简介和基础使用
linux·运维·服务器·nginx·云计算·ansible