【Linux取经路】探索进程状态之僵尸进程 | 孤儿进程(一)

简介: 【Linux取经路】探索进程状态之僵尸进程 | 孤儿进程(一)

2a20624c68f944df9a4474498d058776.gif

一、进程状态概述

进程状态是指在操作系统中,一个进程所处的不同运行状态,进程状态就决定了该进程接下来要执行什么任务。常见的进程状态有以下几种:

新建状态:进程被创建但还没有被操作系统接受和分配资源。

就绪状态:进程已经获得了所需的资源,并等待被调度执行。

运行状态:进程正在执行指令,占用CPU资源。

阻塞状态:进程因等待某个事件(如IO操作)而暂时停止执行,并释放CPU等资源。

终止状态:进程执行完成或被终止,释放所有资源。

1.1 运行状态详解

在上一篇文章【Linux取经路】揭秘进程的父与子提到过,一般的计算机中只有一个 CPU,而进程却可能有很多个,这就注定了 CPU 是一个少量的资源,对所有的进程来说,运行的本质,就是把它放到 CPU 上,所以每个 CPU 都会维护一个运行队列,CPU 以队列的形式对进程做调度。所有的进程要运行都要在运行队列中排队,参与排队的是每个进程的 PCB 对象。所有在运行队列中的进程,它们所处的状态就叫做运行态(R状态)。

1668c88b340744aa8a4bad0554257319.png

一个进程只要把自己放到 CPU 上开始运行,并不是一直要执行完毕,才把自己放下来。如果一个进程被放到 CPU 上直到执行完毕才把自己放下来继续去执行其他进程,那当我们的程序中写了一个 while 死循环出来,在运行该程序的时候,其他的应用就会卡住。但现实并不是这样,我们写了一个 while 死循环,其他程序照样可以正常运行。为了避免这种一个进程长时间占用 CPU 资源的情况出现,提出了时间片的概念。

时间片是操作系统中任务调度算法的一种思想,即将 CPU 的执行时间划分成固定长度的时间段,每个时间段称为一个时间片。在每个时间片内,操作系统将 CPU 分配给一个任务进行执行,当时间片耗尽时,操作系统会中断当前任务,并将 CPU 分配给下一个任务。时间片一般是10毫秒左右,所以在一个时间段内所有的进程代码都会被执行,我们将这种情况叫做并发执行。这种情况下会有大量的把进程放上 CPU 和从 CPU 拿下来的动作,这就叫做进程切换。

1.2 阻塞状态详解

最常见的阻塞状态就是一个进程需要通过键盘读取数据。当一个进程等待从键盘输入的过程,此时该进程就处在阻塞状态。键盘是一种硬件,在冯诺依曼结构体系中属于输入设备(外设),操作系统对硬件资源的管理是先描述再组织,因此每一个硬件都会对应一个结构体对象,该结构体对象中一定会维护一个等待队列,当一个进程需要利用该硬件资源时,进程的 PCB 对象就会被链入该等待队列,此时进程就处于阻塞状态。

6eec771915fa4c4991cceb693745789b.png

小Tips:操作系统中的等待队列可能有成百上千个,不仅每一种硬件有等待队列,进程中也有等待队列,可能会出现一个进程等待另一个进程结束后才能继续运行。不同的操作系统,调度算法也会不同。

1.3 挂起状态详解

在一些操作系统的教材上还会出现挂起状态。无论是运行状态还是阻塞状态,一个进程在没有被 CPU 调度的情况下,它的代码和数据是处于空闲的,即没有被使用。之前说过一个进程在内存中有它自己的代码和数据,还有自己的 PCB 对象,当内存空间告急时,操作系统就会把这些没有被 CPU 调度的进程的代码和数据先放到磁盘中存储,只留进程的 PCB 对象在队列中排队,这种进程就处于挂起状态。

16ca440d94f54cee93df37d64e6ed873.png

上面介绍的这些属于操作系统学科的理论知识,不同的操作系统可能会有不同的实现方案,下面我们来深入看看具体的 Linux 操作系统中有哪些进程状态。

小Tips:挂起状态对用户是不可见的,这是操作系统的一种行为。就像我们把钱存银行里,我们并不知道银行把我们的钱拿去干嘛了,银行可能把我们的钱借出去了或者给员工发工资了等等,我们作为客户不得而知,我们只知道如果存的是活期,可以随时到银行把钱取出来,如果存的是死期只有到期了才能取出来。

二、具体的Linux操作系统中的进程状态

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

2.1 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 */
};

R运行状态(running):并不意味着进程一定在运行中,它表明进程要么是在运行中要么是在运行队列里。

S睡眠状态(sleeping):意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep)),它对应操作系统理论中的阻塞状态。

D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待 IO 的结束。

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

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

2.2 查看进程状态

先来看看下面这段代码执行起来后的进程状态。

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

1f89d005d3a3482898ed85d15fe16d8d.png

可以看出这段代码执行起来后的进程状态是 S睡眠状态,将 while 循环中的打印去掉再去执行代码看看进程状态。

int main()                                                    
{                                                             
    while(1);                                                  
    return 0;    
}  

3471d16d5e2141cf92ae6fcd91996109.png

此时代码中只剩一个 while 死循环,去执行这段代码,进程状态变成了 R运行状态。为什么会出现在这种情况呢?原因是 CPU 的执行速度是非常快的,第一段代码中的 printf 是要去频繁的访问显示器设备,而我们的显示器可能并不能被该进程直接去写入,所以该进程大部时间都在显示器的等待队列里等待显示设备就绪,因此最终查出来的进程状态是 S睡眠状态。当我们去掉 printf 之后,该进程就不会去访问显示器设备,始终都在运行队列里,所以最终查出来的进程状态是 R运行状态。

小Tips:查询结果中显示的+表示该进程在前台运行,这意味我们此时在 bash 命令行输指令是不会有任何反应的,可以在输入指令的后面加上&,此时表示让该进程在后台运行,要终止掉该进程只能通过指令kill -9 进程PID。


目录
相关文章
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
471 32
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
395 67
|
11月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
305 16
|
11月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
213 20
|
10月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
229 0
|
10月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
298 0
|
10月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
179 0
|
10月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
240 0
|
存储 网络协议 Linux
【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件
本文详细介绍了Linux中的进程IO与系统调用,包括 `open`、`write`、`read`和 `close`函数及其用法,解释了文件描述符(fd)的概念,并深入探讨了Linux中的“一切皆文件”思想。这种设计极大地简化了系统编程,使得处理不同类型的IO设备变得更加一致和简单。通过本文的学习,您应该能够更好地理解和应用Linux中的进程IO操作,提高系统编程的效率和能力。
608 34

热门文章

最新文章