【Linux】进程概念(下)

简介: 【Linux】进程概念(下)

👉进程状态👈


进程状态的普遍理解


操作系统的书籍一般都会给我们罗列出很多进程状态,比如:运行、新建、就绪、挂起、阻塞、等待和死亡等等。如此之多的概念,总会让我们学起来比较费劲。那操作系统会有如此之多的进程状态呢?其实是为了满足不同的运行场景。


对于人来说,对一件事的认识是不太可能建立在想象之上的。所以,我们先来了解一下操作系统的空间概念,看看普遍的操作系统层面是如何理解上面罗列的进程状态的。


运行、阻塞和挂起状态的讲解

1dcb7bfe78e2480994f68f39aac7cb9d.png

Linux 系统的进程状态


以上是操作系统书籍对进程状态概念的定义,那么接下来我们就学习一下操作系统中具体的进程状态!


进程状态的描述

2d9d25ac8f0f4651a9cd93ea5c3e9091.png


  • R 运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
  • S 睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠。
  • D 磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待 IO 的结束。

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

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


406abc7c6d2140bd8a2e1f0b2dcb5e52.png


1.观察运行状态 R

fcf245ee5ca4426d81211d529ca19b9e.png

763d928cdff8477a8e64c48bb79dd2dc.png


上图的 R 就是运行状态,后面的 + 号以后会提及。


2.观察休眠状态 S

bd8a79494820470b9355e25d1c9481a3.png


1f35f5e4d42640edb6fbdc7be4513d27.png


在我们看来,我们的程序是一致在运行的,那为什么进程状态是休眠状态呢?其实是因为 printf 函数是将字符串打印到显示器(外设)上的,而显示器的速度是比较慢的,需要等待显示器就行要花比较长的时间(对 CPU 而言)。所以 99 % 的时间都是等 IO 就绪,1% 的时间在执行打印代码,所以我们查到的进程状态绝大多数是休眠状态。


注:需要访问外设的进程,其状态绝大多数时间是休眠状态 S,也是阻塞状态的一种。


3.查看暂停状态 T

46cdc95b84fc433ead2db4478e76534c.png


kill - 19 PID #使处于运行状态的进程改为暂停状态

e05dd706be7f487499db06717367dec5.png


注:暂停状态也是阻塞状态的一种,处于暂停状态的进程不知道是否被挂起,由操作系统决定。


kill - 18 PID #使处于暂停状态的进程改为运行状态


6fee193e66264844be0978eee12f7528.png


可以看到,此时的运行状态和最开始的运行状态相比,少了一个 + 号。能通过 Ctrl + c 键杀死的进程是前台进程,不能通过 Ctrl + c 键杀死的进程是后台进程。前台进程的状态比后台进程的状态多了一个 + 号。只能通过kill -9 PID来杀死后台进程。


注:在 Linux 系统中是看不到挂起状态的。因为用户只需要关心自己的进程是运行状态、休眠状态还是暂停状态,并不需要关心挂起状态。挂起状态是操作系统做内存管理将进程的代码和数据保存到磁盘上,我们并不需要知道,所以我们在 Linux 系统下是看不到挂起状态的。


4.深度睡眠状态 D


上面提到的休眠状态 S 是浅度睡眠状态,该状态是可以被终止的!而深度睡眠状态是很少见的,常见于高 IO、高并发的场景。在该状态下的进程,无法被操作系统杀死,只能通过断点或者进程自己醒来来解决。深度睡眠的状态只见于高 IO 的情况,大家可以通过dd指令浅浅地逝一下。


eeb54a0c7b2c4308a100b53e9a36e54b.png


5.正在被追踪状态 t


d110ffb720ea435492500cbc05a83977.png


注:T(tracing stop) 是暂停状态的一种,该状态 t 表示该进程正在被追踪(调试)。


Makefile 新语法


efb9a139553a44debb0b78eb8910b328.png

6.死亡状态 X


操作系统的书籍上都会给我们介绍进程的死亡状态,而在 Linux 系统中,我们无法验证一个进程是否死亡。当进程死亡时,操作系统会立即或延迟进程占用的资源。


7.僵尸状态 Z


  • 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。
  • 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。

所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入 Z 状态。


进程被创建出来,就为了帮助操作系统或者用户完成某些任务。那对于操作系统和用户来说,肯定会关心该进程把任务完成的如何。那么进程退出的时候,就不能立即释放该进程对应的资源,而应该保存一段时间,让父进程或者操作系统来读取进程退出结果。如果父进程不读取子进程的退出结果,就会造成僵尸进程。


如何创建处于僵尸状态的进程?只要子进程退出,父进程还在运行,但父进程没有读取子进程的状态,子进程就会进入僵尸状态 Z。


c4e2ff656dc84a6289c4c00c5cfe5760.png


while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep; sleep 1; done #自动化监控脚本
#-v选项 grep搜索时过滤掉指定关键词


306b67594585413d9eabdd8ccc501acf.png


注:僵尸进程是有很大危害的,这个问题到进程控制模块会讲解!


僵尸进程的危害


  • 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于 Z 状态。
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在 task_struct(PCB) 中。换句话说, Z 状态一直不退出, PCB 一直都要维护。

那一个父进程创建了很多子进程,就是不回收子进程,就会造成内存资源的浪费。因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间。

僵尸进程不解决会造成内存泄漏问题!!!


👉孤儿进程👈


  • 父进程如果提前退出,那么子进程后退出,进入 Z之后,那该如何处理呢?
  • 父进程先退出,子进程就称之为 “孤儿进程”。
  • 孤儿进程被1号 init 进程领养,当然要有 init 进程回收喽。
  • 如果是前台进程创建的子进程变成了孤儿进程,那么该孤儿进程会自动变成后台进程。


d2494f60afa848f0b3cd50ff957ee3af.png



c38b94ce14d34e18b7b65e62b4126c3a.png


输入 kill -9 父进程PID 杀死父进程后,子进程就会被1号进程领养。那为什么看不到父进程变成僵尸进程呢?因为父进程也有父进程,其父进程是 bash,将其资源回收了,所以我们就看不到父进程的僵尸状态了。


1号进程就是操作系统!


871d084e3b42463196506999b94d4c9b.png


👉进程优先级👈


基本概念


  • CPU 资源分配的先后顺序,就是指进程的优先级(priority)。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的 Linux 很有用,可以改善系统性能。

还可以把进程运行到指定的 CPU 上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。


优先级和权限的区别:权限是能不能的问题,而优先级是谁先谁后的问题。为什么要存在优先级?因为资源太少了。优先级本质是 PCB 中的一个或者几个整数数字。


查看进程优先级


7291523febc84084999ade30cf0a4927.png


ps -la #查看进程的优先级

b627ae8c6450476789ed2e2525bb0d32.png



  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的 nice 值



PRI 和 NI


  • PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高。
  • 那 NI 呢?就是我们所要说的 nice 值了,其表示进程可被执行的优先级的修正数值。

进程的 PRI 值越小就越快被执行,那么加入 nice 值后,将会使得 PRI 变为:PRI(new)=PRI(old)+nice

这样,当 nice 值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行。

所以在 Linux 系统下,调整进程优先级就是调整进程的 nice 值。

nice 值的取值范围是 -20 至 19,一共 40 个级别。

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

默认情况下,进程的 nice 值为 0,PRI(old) 为 80。



修改 nice 值


  • sudo top
  • 进入 top 后按 “r” –> 输入进程 PID –> 输入 nice 值


b65dc9913d184d58adc87e0754c705fb.png

830e45dcf8e94959bca900cfb57c5ba5.png


注:nice 值的设置范围是 -20 到 19,设置太大或太小都不会超过该范围。因为 nice 值太大或太小都会影响 CPU 调用进程的公平性。每次修改 nice 值,都是在 PRI = 80 的基础上修改的。


👉其他概念👈


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


注:CPU 调度进程的方式,并不是将该进程执行完再去执行另一个进程,而是采取时间片轮转的方式来调度进程的。也就是将时间段切分为很多的小时间片,这个时间片来调度这个进程,这个时间片过后,该进程执行完毕或者重新到运行队列中排队。到了下一个时间片,就会去调度另外一个进程。这样,在一段时间内,多个进程都能够得以推进,这也就是并发。


👉进程切换👈


  • CPU 内部只有一套寄存器硬件,CPU 中的寄存器 eip (pc 指针) 可以保存当前正在执行指令的下一条指令的地址,寄存器里面保存的数据是属于当前进程的。寄存器硬件不等于寄存器内的数据!
  • CPU 调度进程需要做的三件事:取指令、分析指令和执行指令。
  • 进程在运行的时候需要占用 CPU,但进程并不是一直要占用 CPU 到进程结束的! 进程在运行的时候都会有自己的时间片, 进程运行时一定会产生非常多的临时数据,也称为上下文,这些数据属于当前进程!当进程的时间片跑完了,该进程产生的临时数据需要保存到操作系统的段描述符中,这也称为上下文保护。当该进程再次运行起来时,需要将临时数据恢复,从上一次执行的地方开始运行起来,这也称为上下文恢复。

    进程在切换的时候,要进行进程的上下文保护;当进程恢复运行的时候,要进行上下文的恢复!

    寄存器内的数据只属于当前运行的进程。寄存器被所有进程共享,寄存器内的数据是每个进程各自私有的上下文数据。



👉总结👈


本篇博客主要讲解了进程状态的普遍理解、Linux 系统的进程状态、僵尸进程、孤儿进程、进程优先级、并行和并发以及进程切换等。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️
















相关文章
|
11月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
373 67
|
10月前
|
NoSQL Linux 编译器
GDB符号表概念和在Linux下获取符号表的方法
通过掌握这些关于GDB符号表的知识,你可以更好地管理和理解你的程序,希望这些知识可以帮助你更有效地进行调试工作。
426 16
|
10月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
284 16
|
10月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
201 20
|
9月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
214 0
|
9月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
285 0
|
9月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
168 0
|
9月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
230 0
|
12月前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
450 4
|
12月前
|
Linux 数据库 Perl
【YashanDB 知识库】如何避免 yasdb 进程被 Linux OOM Killer 杀掉
本文来自YashanDB官网,探讨Linux系统中OOM Killer对数据库服务器的影响及解决方法。当内存接近耗尽时,OOM Killer会杀死占用最多内存的进程,这可能导致数据库主进程被误杀。为避免此问题,可采取两种方法:一是在OS层面关闭OOM Killer,通过修改`/etc/sysctl.conf`文件并重启生效;二是豁免数据库进程,由数据库实例用户借助`sudo`权限调整`oom_score_adj`值。这些措施有助于保护数据库进程免受系统内存管理机制的影响。