【从浅学到熟知Linux】进程状态与进程优先级(含进程R/S/T/t/D/X/Z状态介绍、僵尸进程、孤儿进程、使用top及renice调整进程优先级)

在这里插入图片描述

🏠关于专栏:Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程及数据库等内容。
🎯每天努力一点点,技术变化看得见

文章目录

  • 进程状态
    • 进程状态查看
    • R运行状态(running)
    • S睡眠状态(sleeping)
    • D磁盘休眠状态(Disk sleep)
    • T停止状态(stopped)
    • t调试/追踪状态(tracing stop)
    • X死亡状态/终止状态(dead)
    • Z僵尸状态/僵尸进程(zombie)
  • 孤儿进程
  • 进程优先级
    • 基本概念
    • 查看系统进程
    • PRI及NI
    • 修改进程优先级
      • top命令
      • renice命令
    • 关于进程的相关概念


进程状态

关于进程状态,我们来看看Linux源代码中总共有几种状态↓↓↓

static const char* cinst task_state_array[] = {
"R(runnning)",/* 0 */
"S(sleeping)",/* 1 */
"D(disk sleep)", /* 2 */
"T(stopped)",/* 3 */
"t(tracing stop)",/* 4 */
"X(dead)", /* 16 */
"Z(zombie)" /* 32 */
};

在介绍这些状态时,将使用使用描述+代码验证的方式(但部分状态无法使用代码验证)。在开始介绍前,我们需要了解如何查看进程状态↓↓↓

进程状态查看

ps aux / ps axj

查看进程状态总共有两种方式,分别是ps auxps axj。使用它们查看进程的效果如下图所示↓↓↓
在这里插入图片描述
★ps:关于ps命令的更多用法,可以查询man手册。

R运行状态(running)

我们在创建了进程之后,操作系统会给该进程创建一个task_struct结构体,该结构体中包含进程状态、pid、ppid、优先级等字段,该结构体就是PCB(进程控制块),用于记录进程各类信息。

管理好这些进程,我们需要只要管理好task_struct结构体即可。因此,操作系统将task_struct链成一个链表(队列)。
在这里插入图片描述
由于计算机中的各类资源(包括CPU、内存、外部设备等)均十分宝贵,各个进程在获取某个资源时,可能需要到某个资源上排队。而等待CPU资源的进程将被链成一个队列,这个队列叫做运行队列(run_queue)。而处于运行队列上的进程的状态就是运行状态,即R状态

下面,我们编写一个死循环,并查看该进程的状态↓↓↓

#include <stdio.h>
int main()
{while(1){}return 0;
}

在这里插入图片描述
在这里插入图片描述
上面的STAT的R就是运行状态。

S睡眠状态(sleeping)

如果我们编写一个循环打印"hello world"的程序,则执行该程序的进程的状态是R状态吗?

#include <stdio.h>
int main()
{while(1){printf("hello world\n");}retrun 0;
}

在这里插入图片描述

这里我执行ps axj | head -1 && ps axj | grep test命令,得到的进程状态是S状态,即睡眠状态。这是为什么呢?那什么是睡眠状态呢?

我们在执行上面的程序时,进程需要访问外设,而外设相比与cpu而言,速度非常慢。该进程为了打印"hello world",它需要到对应的外设上等待(这里的外设是显示器),在它需要使用外设资源时,cpu将该进程的PCB从运行队列中取下来,并链入显示器的等待队列中。在除了cpu以外的队列中等待时,这时的状态就是S休眠状态。等该进程打印完毕后,再链入cpu,继续向下执行。但由于上面的程序频繁访问外设,导致它在运行队列中的时间非常短。因而,我们在查看该进程状态时,绝大多数情况下,它都处于睡眠状态。

在这里插入图片描述

D磁盘休眠状态(Disk sleep)

在操作系统中,如果一个进程处于睡眠状态,即S状态。如果此时操作系统负载过大,则可能杀死该进程。这也就是为什么某些软件服务在用户量过大时,出现某些用户无法获取服务的原因。

从操作系统角度来说,操作系统为了维护服务器能稳定运行,不得不杀死某些进程;从进程角度来说,进程正常运行而被操作系统强制关闭,进程也无能为力。

如果我们希望某些关键性进程,即使在操作系统负载过大时也不会被杀死,则可以将该进程设置为D状态,即磁盘休眠状态(也称为磁盘睡眠状态、深度睡眠状态)。处于该状态的进程不能被操作系统中断,也不能被操作系统唤醒。该进程只有自己醒来,才能被操作系统调度执行;只有该进程执行完毕,才能被操作系统回收。

★ps:该状态无法使用程序演示

T停止状态(stopped)

在操作系统中,可以给某些进程发送信号,发送信号的格式为:

kill -[信号编号] [进程pid]

下面,我们使用kill -l查看所有信号及其对应的编号↓↓↓
在这里插入图片描述
上图的18号信号SIGCONT为进程继续执行信号,19号信号为SIGSTOP为进程暂停信号。如果我们给某个进程发送19号信号,则它将处于T状态,即暂停状态。

下面,我们给上面循环打印"hello world"的进程发送19号信号,再对比发送信号前后的状态变化

kill -19 19093

在这里插入图片描述
在这里插入图片描述
在接收到19号SIGSTOP信号后,19093号进程停止打印"hello world",并且此时它的状态为T状态,即暂停状态。

如果我们给19093号进程发送18号SIGCONT信号,会是什么效果呢?
在这里插入图片描述
发送信号后,19093号进程继续打印"hello world",并且它的状态又变回S状态,即睡眠状态。但这里不同的是,原先的状态是S+,而此时的状态是S。这两者有什么区别呢?

S+状态下的进程,在使用ctrl+C时,可以被终止;而S状态下的进程使用ctrl+C却无法被终止。这里带有+号的称为前台进程,不带+号的称为后台进程。后台进程需要使用kill -9 [进程号]发送9号信号来终止。
在这里插入图片描述

★ps:T状态与S状态的区别:T状态单纯暂停,并不等待某种资源;而S状态是为了等待某种资源。

t调试/追踪状态(tracing stop)

我们在编写完程序后,可以在使用gcc编译,如果在编译命令的末尾加上-g选项,则会生成一个debug版本的程序。如果不带-g选项,gcc默认生成的是release版本。

我们使用gcc生成下面程序的release和debug版本↓↓↓

#include <stdio.h>int Add(int left, int right)
{return left + right;
}int main()
{int num1 = 10;int num2 = 20;printf("%d + %d = %d\n", num1. num2, Add(num1, num2));return 0;
}

在这里插入图片描述
从上图可以发现,debug版本所占的内存空间会大于release版本(因为debug版本中包含调试信息)。

下面我们使用gdb对test_g进行调试↓↓↓
在这里插入图片描述
由于在12行处打了断点,此时程序停止在12行处。我们使用ps axj | head -1 && ps axj | grep test查看当前进程状态↓↓↓
在这里插入图片描述
此时的进程状态为t状态,即调试状态(也称为追踪状态)。

X死亡状态/终止状态(dead)

如果进程执行结束了,操作系统会马上回收该进程的资源吗(进程此时占用内存等资源)?不一定。如果此时cpu上此时正在处理更加重要、紧急的进程,则操作系统此时不会马上回收已经执行结束的进程,而是将该进程标识为X状态,即死亡状态(也成为终止状态)。

标记为X状态的进程,表示该进程可以被操作系统回收。但具体什么时候回收,取决于操作系统。由于X状态瞬时性较强,难以使用程序演示,这里就不使用程序演示了。

Z僵尸状态/僵尸进程(zombie)

僵尸状态(zombie,也称为僵死状态)是一种比较特殊的状态。该状态发生在子进程退出,而父进程没有回收子进程资源时(即父进程没有使用waitpid读取子进程的退出信息),此时子进程就会进入僵尸状态。

僵尸进程会以终止状态保持在进程表中,并且会一直等待父进程读取退出状态码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,则子进程会进入Z状态。

下面创建的程序,使得子进程保持5秒的僵尸状态↓↓↓

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t id = fork();assert(id != -1);if(id == 0){printf("I am child process! pid = %d, ppid = %d\n", getpid(), getppid());sleep(5);exit(0);}printf("I am parent process! pid = %d\n", getpid());sleep(10);return 0;
}

执行上述程序并使用while :; do ps axj | head -1 && ps axj | grep test; sleep 1; echo "#############" done; 脚本,每1秒钟对执行内容做监视。
在这里插入图片描述
在这里插入图片描述
我们可以发现,在子进程退出后,父进程没有退出,此时的子进程的状态变为Z状态,即僵尸状态。

僵尸进程的危害:
进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态。

维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护。

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

★ps:关于僵尸进程如何被处理的问题,将在后序文章中的介绍。

孤儿进程

上面已经将进程的各种状态讲述完毕,接下来,我们再了解另一种进程——孤儿进程。

父进程如果提前退出,子进程后退出,子进程进入Z之后,那该如何处理呢?

如果让子进程一直保持Z状态,则会造成内存泄漏;但此时子进程的父进程已经执行结束,没有进程可以来清理子进程的资源了,这种子进程被称为孤儿进程。操作系统为了解决这个问题,对于父进程已经执行结束,而子进程后退出的,该子进程将被1号init进程领养,其资源将由init进程进行回收。

下面代码中,父进程比子进程执行结束前5秒就退出↓↓↓

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t id = fork();assert(id != -1);if(id == 0){int cnt = 10;while(cnt > 0){printf("I am child process, pid = %d, ppid = %d\n", getpid(), getppid());sleep(1);cnt--;}exit(0);}printf("I am parent process, pid = %d\n", getpid());sleep(5);return 0;
}

在这里插入图片描述
由程序执行结果可以看出,子进程前5秒的父进程pid为15480,由于父进程在子进程推出前5秒就推出了,此时子进程被1号init进程领养,故此时该进程的父进程pid为1。

进程优先级

基本概念

优先权高的进程有优先执行权利,可以优先获得cpu资源。

配置进程优先权对多任务环境的linux很有用,可以改善系统性能。对于多核计算机,可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

查看系统进程

我们可以执行ps -le来查看系统中所有进程的详细信息(-e选项表示所有进程,-l选项表示显示进程详细信息)
在这里插入图片描述
上图中:
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个级别。

那如果PRI(new)=PRI(old)+nice,那么我的程序起始优先级PRI为80,我对它重复设置10000次nice值为-20,它的优先级PRI是不是变成80-20*10000呢?答案是否定的。在Linux操作系统中,PRI起始都为80,nice值得范围为-19到20。当我们设置了新的nice值时,该进程的PRI=80+nice值。也就是说PRI的范围在[80-20,80+19]之间。

★ps:进程的nice值不是进程的优先级,进程优先级与nice值不是一个概念,但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据。

修改进程优先级

top命令

首先,我们运行一个名为test的死循环程序。此时它的PRI为80,NI为0。
在这里插入图片描述
top命令修改进程优先级的方法(如果要设置小于0的nice值,即提高进程优先级,此时需要使用sudo提权):

①执行top命令
在这里插入图片描述
②输入r,并输入待修改进程优先级的进程pid。
在这里插入图片描述
③输入nice值,这里输入10。
在这里插入图片描述
我们使用ps -el | head -1 && ps -el | grep test查看进程优先级发现,test的PRI变为90,NI变为10。
在这里插入图片描述
★ps:上图中,我们将nice值设置为10,则该进程的PRI=80+10=90。如果我们在此基础上设置nice值为15,则该进程的优先级为PRI=80+15=95。

renice命令

renice命令使用格式为:

renice [nice值] -p [进程pid]

下图演示将20269号进程的nice值修改为15。
在这里插入图片描述
我们使用ps -el | head -1 && ps -el | grep test查看进程优先级发现,test的PRI变为95,NI变为15。
在这里插入图片描述
★ps:如果要给进程设置比原nice值更小的nice值,需要使用sudo提权。

关于进程的相关概念

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

关于并行和并发这里做一下更详细的解释:
并行就是多个进程同时执行。而并发并不是,例如我们有3个进程在一个CPU上并发执行,第1个进程先执行1ms,接下来由第2个进程执行1ms,再由第3个进程执行1ms,然后又由第1个进程执行,以此类推…像这种明明各个进程是交替执行的,但由于各个进程都在向前运行,而进程交替运行的操作用户感知不到,用户以为这3个进程是各占用1个CPU并同时执行的,这种被称为并发。

🎈欢迎进入从浅学到熟知Linux专栏,查看更多文章。
如果上述内容有任何问题,欢迎在下方留言区指正b( ̄▽ ̄)d

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

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

相关文章

蓝桥杯嵌入式速成

蓝桥杯嵌入式速成 cubmx创建工程利用官方提供的LCD代码创建工程&#xff08;15届不能用&#xff09;利用官方提供的LCD代码创建工程&#xff08;15届能用&#xff09;Keil配置头文件注意其他注意 LED闪烁 按键短按长按双击 LCD高亮行高亮字符 RTCADCI2Cuart接收发送 PWMDAC定时…

Vue.js------vue基础

1. 能够了解更新监测, key作用, 虚拟DOM, diff算法2. 能够掌握设置动态样式3. 能够掌握过滤器, 计算属性, 侦听器4. 能够完成品牌管理案例 一.Vue基础_更新监测和key 1.v-for更新监测 目标&#xff1a;目标结构变化, 触发v-for的更新 情况1: 数组翻转情况2: 数组截取情况3…

VIT论文阅读

论文地址&#xff1a;https://arxiv.org/pdf/2010.11929.pdf VIT论文阅读 摘要INTRODUCTION结论RELATEDWORKMETHOD1.VISIONTRANSFORMER(VIT)整体流程消融实验HEAD TYPE AND CLASSTOKENpoisitional embedding 整体过程公式Inductive biasHybrid Architecture 2.FINE-TUNINGANDH…

Substance 3D2024版 下载地址及安装教程

Substance 3D是Adobe公司推出的一套全面的3D设计和创作工具集合&#xff0c;用于创建高质量的3D资产、纹理和材质。 Substance 3D包括多个功能强大的软件和服务&#xff0c;如Substance 3D Painter、Substance 3D Designer和Substance 3D Sampler等。这些工具提供了广泛的功能…

TQ15EG开发板教程:在MPSOC上运行ADRV9009

首先需要在github上下载两个文件&#xff0c;本例程用到的文件以及最终文件我都会放在网盘里面&#xff0c; 地址放在最后面。在github搜索hdl选择第一个&#xff0c;如下图所示 GitHub网址&#xff1a;https://github.com/analogdevicesinc/hdl/releases 点击releases选择版…

vue实现海康h5player问题汇总

1. 引入问题 最开始写的时候&#xff0c;把h5player封装成了一个组件&#xff0c;把资源文件随便放在了一个目录下&#xff0c; 直接在子组件中引入&#xff0c;报错window.JSPlugin is not a constructor 或者JSPlugin is not defined 初步分析应该是引入资源文件失败&#x…

Java异常处理机制详解:多层方法调用与异常传播(day23)

1.数组下标越界 2.多个处理异常 上面这两个代码的区别就是有无 System.out.println("抛出了NumberFormatException"); System.out.println("抛出了ArrayIndexOutOfBoundsException"); 第一种是不论捕获到哪种异常&#xff0c;都只会调用e.printStack…

Asterisk 21.2.0编译安装经常遇到的问题和解决办法之pjproject

目录 Asterisk社区官方的说法然而买家秀是这样的pjproject-2.14下载不了的问题如何解决 Asterisk社区官方的说法 编译安装Asterisk 21.2.0版本 按照官网文档&#xff0c;原则上只需要如下几步&#xff1a; ./contrib/scripts/install_prereq install ./configure make make i…

Golang | Leetcode Golang题解之第20题有效的括号

题目&#xff1a; 题解&#xff1a; func isValid(s string) bool {n : len(s)if n % 2 1 {return false}pairs : map[byte]byte{): (,]: [,}: {,}stack : []byte{}for i : 0; i < n; i {if pairs[s[i]] > 0 {if len(stack) 0 || stack[len(stack)-1] ! pairs[s[i]] {…

【leetcode面试经典150题】36. 旋转图像(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

第04章 计算机常用通信指标和术语视频课程

4.1 本章目标 掌握bit、Byte、KB、MB、GB、TB概念和换算关系掌握波特率、比特率、误码率的概念掌握信道、基带信号、频带信号概念了解多路复用、频分多路复用、时分多路复用了解同步传输、异步传输概念 4.2 bit、Byte、KB、MB、GB、TB概念和换算关系 4.2.1 概念与换算 4.2.2…

docker-compose 之 OpenGauss

使用 docker 启动高斯数据库的示范脚本如下&#xff1a; docker-compose.yml version: 3.7 services:opengauss:image: enmotech/opengauss:5.1.0container_name: opengaussnetwork_mode: "host"privileged: truevolumes:- ./opengauss:/var/lib/opengaussenvironm…

使用自己的数据基于SWIFT微调Qwen-Audio-Chat模型

目录 使用自己的数据训练参数设置自己的数据准备语音转写任务语音分类任务 开始训练不同训练方法mpddpmp ddpdeepspeed 训练实例训练详情Qwen-Audio-Chat模型 模型数据实例官方可用的数据由内部函数处理为指定格式 训练好的模型测试 使用自己的数据 官方参考文档&#xff1a;…

CSPNet: A New Backbone that can Enhance Learning Capability of CNN

CSPNet 摘要1.引言3.方法3.1Cross Stage Partial NetworkDenseNetCross Stage Partial DenseNetPartial Dense BlockPartial Transition LayerApply CSPNet to Other Architectures 3.2 Exact Fusion ModelLooking Exactly to predict perfectlyAggregate Feature PyramidBalan…

【Android】【root remount】【3】remount 文件详细信息获取

前言 我们在root & remount 设备后&#xff0c;push相关文件到systm 、vendor、product 等目录进行调试&#xff0c;那么我们push的文件被保存在什么地方呢&#xff1f; 以及我们FWS、app侧如何过去push 的文件信息呢&#xff1f; remount push 文件保存 push 文件保存的…

java数据结构与算法刷题-----LeetCode684. 冗余连接

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 并查集 并查集 解题思路&#xff1a;时间复杂度O( n ∗ l o g 2…

高质量数据赋能大模型应用落地,景联文科技提供海量AI大模型数据

随着人工智能技术的迅猛进步&#xff0c;AI算法持续创新突破&#xff0c;模型的复杂度不断攀升&#xff0c;呈现出爆炸性的增长态势。数据的重要性愈发凸显&#xff0c;已然成为AI大模型竞争的核心要素。 Dimensional Research的全球调研报告显示&#xff0c;72%的受访者认为&a…

01、ArcGIS For JavaScript 4.29对3DTiles数据的支持

综述 Cesium从1.99版本开始支持I3S服务的加载&#xff0c;到目前位置&#xff0c;已经支持I3S的倾斜模型、3D Object模型以及属性查询的支持。Cesium1.115又对I3S标准的Building数据实现了加载支持。而ArcGIS之前一直没有跨越对3DTiles数据的支持&#xff0c;所以在一些开发过…

【Qt】:对话框(一)

对话框 一.基本的对话框二.自定义对话框三.通过图形化界面自定义对话框四.关于对话框mode 对话框是GUI程序中不可或缺的组成部分。一些不适合在主窗口实现的功能组件可以设置在对话框中。对话框通常是一个顶层窗口&#xff0c;出现在程序最上层&#xff0c;用于实现短期任务或者…

读所罗门的密码笔记16_直通心智

1. 直通心智 1.1. 如今&#xff0c;科学家已经可以诱发触觉、压觉、痛觉和大约250种其他感觉 1.1.1. DARPA支持的触觉技术第一次让一位受伤的人能够用假肢和手指感知到被触碰的物体 1.1.2. 可以建立人工系统&#xff0c;来替换和弥补受损大脑的部分区域 1.1.3. 神经科学家能…