【从浅学到熟知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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CentOS安装MeterSphere并实现无公网IP远程访问本地测试平台

文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 前言 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能&am…

电脑出现正在清理已完成100%,出现正在清理已完成0%,正在准备windows请不要关闭你的计算机,电脑出现dell图标,下方没有小的旋转圆圈

1.开机发现停留在dell图标。在正上方。和平时不一样。下方没有小的旋转圆圈 2.长按电源键5秒重启 3.电脑重启后。显示正在准备windows请不要关闭你的计算机 4.电脑自动重启 5.电脑出现正在清理已完成0%&#xff0c;等了大概十几分钟 6.电脑出现正在清理已完成100%&#xff0c;等…

图片尺寸在线怎么修改大小?利用图片在线处理工具解决

在社交媒体平台上分享照片是我们日常生活中常见的活动之一。有时&#xff0c;我们需要调整照片的尺寸以适应社交媒体平台的要求。在线修改图片尺寸的工具可以帮助我们快速调整照片的大小&#xff0c;确保其在社交媒体上显示完整且美观。 压缩图网站&#xff0c;点击“图片改大…

Operation is not supported on this platform.

.net core 中&#xff1a; Action<string> action this.DoSome; action.BeginInvoke("button1_Click", null,null);执行报错&#xff1a; System.PlatformNotSupportedException:“Operation is not supported on this platform.”原因&#xff1a; .NET C…

基于YOLOv8的光栅检测系统(Python源码+Pyqt6界面+数据集)

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文摘要&#xff1a;基于YOLOv8的光栅检测系统&#xff0c;并阐述了整个数据制作和训练可视化过程&#xff0c;最后通过Pyside UI界面进行展示。 博主简介 AI小怪兽&#xff0c;YOLO骨灰级玩家&#xff0c;1&#xff09;YOLOv5、v7、…

网络IO模型以及实际应用

网络IO模型 本文主要介绍了几种不同的网络IO模型&#xff0c;以及实际应用中使用到的Reactor模型等。 我们常说的网络IO模型&#xff0c;主要包含阻塞IO、非阻塞IO、多路复用IO、信号驱动IO、异步IO。 根据第一个阶段&#xff1a;是否需要阻塞&#xff0c;分为阻塞和非阻塞IO。…

BMS系统必要参数介绍

系统参数打印解释 (1)Battery Real Capacity:表示电池实际容量值&#xff08;额定容量值是出厂给的&#xff0c;SOH电池健康度计算也可以用实际值/额定值&#xff09; (2)Battery Remain Capacity&#xff1a;表示电池剩余容量值 (3)Battery SOC&#xff1a;电池剩余容量百分比…

头歌-机器学习 第12次实验 Adaboost算法

第1关&#xff1a;什么是集成学习 任务描述 本关任务&#xff1a;根据本节课所学知识完成本关所设置的选择题。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.什么是集成学习。 什么是集成学习 集成学习方法是一种常用的机器学习方法&#xff0c;分为b…

Unity 遮罩

编辑器版本 2017.2.3f1 学习Unity的三张遮罩方式 1. Mask 遮罩方式 首先&#xff0c;在界面上创建2个Image&#xff0c;一个命名Img_Mask,大小设置 400* 400&#xff0c; 一个命名Img_Show,大小设置500*500。 然后&#xff0c;给 Img_Mask添加Mask,选择Img_Mask,点击Add Com…

面试算法-170-二叉树的最大深度

题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 解 class Solution {public int maxDepth(TreeNod…

卷积运算及实现

本文介绍卷积运算及实现。 1.定义 线性时不变系统的输出是输入样本与系统的冲激响应的卷积。这里假设输入样本为x(n)&#xff0c;系统冲激响应为h(n)&#xff0c;系统输出为y(n)&#xff0c;则 线性卷积计算过程包含以下4个步骤&#xff1a; 1)折叠&#xff0c;关于l0&#…

The C programming language (second edition,KR) exercise(CHAPTER 2)

E x c e r c i s e 2 − 1 Excercise\quad 2-1 Excercise2−1&#xff1a;输出结果如图1和图2所示&#xff0c;这道练习题需要文章1和文章2的知识。 #include <stdio.h> #include <limits.h>float getFloat(char sign, unsigned char exp, unsigned mantissa); do…

抖音小店无货源怎么做?新型无货源玩法,帮商家躲避无货源处罚!

大家好&#xff0c;我是电商糖果 关于现在抖店的商家&#xff0c;是谈“无货源”色变&#xff0c;被平台罚怕了。 动不动就是扣分&#xff0c;扣2000的保证金&#xff0c;商家是苦不堪言。 又不舍得放弃抖音小店现在热度和风口。 糖果做抖音小店无货源有四年时间了&#xf…

WritableComparable排序案例实操

文章目录 WritableComparable排序概述第一个案例需求&#xff08;全排序&#xff09;代码实现结果分析 第二个案例需求&#xff08;二次排序&#xff09;问题分析和代码结果分析 第三个案例需求&#xff08;区内排序&#xff09;需求分析代码实现结果分析 WritableComparable排…

材料物理 笔记-5

原内容请参考哈尔滨工业大学何飞教授&#xff1a;https://www.bilibili.com/video/BV18b4y1Y7wd/?p12&spm_id_frompageDriver&vd_source61654d4a6e8d7941436149dd99026962 或《材料物理性能及其在材料研究中的应用》&#xff08;哈尔滨工业大学出版社&#xff09; 半…

激光测距漫反射板

激光测距漫反射板是一种重要的光学元件&#xff0c;广泛应用于工业测量、自动化控制、机器人导航等领域。自动驾驶技术的发展日新月异&#xff0c;其中激光测距技术在自动驾驶车辆中发挥着至关重要的作用。而激光测距反射板作为激光测距的关键组件之一&#xff0c;其性能和应用…

基于RKNN的YOLOv5安卓Demo

1.简介 基于RKNPU2 SDK 1.6.0版的安卓YOLOv5演示应用程序&#xff0c;选择图片进行对象检测并显示识别结果。 GitHub源码地址&#xff1a;https://github.com/shiyinghan/rknn-android-yolov5 2.实现过程 参考RKNN官方库RKNN Model Zoo提供的YOLOv5对象检测demo&#xff0c…

短袖怎么选质量好?5款质量好的短袖T恤

最近天气逐渐开始变热了&#xff0c;不少朋友都在考虑选什么短袖比较好。由于现在市面上的短袖品牌实在太多&#xff0c;并且还有很多做工差、面料不好的短袖混杂在其中&#xff0c;让大家挑选短袖十分困难。为此我特意进行了一次短袖测评&#xff0c;总结出几点选购方法&#…

C++ 之 newmat 矩阵运算库使用笔记

文章目录 Part.I IntroductionChap.I newmat 简介 Part.II 安装与编译Chap.I 直接使用源码Chap.II 基于 CMake 使用源码Chap.III 编译成库 Part.III 关于矩阵的构造与运算Chap.I 矩阵的构造与初始化Chap.II 矩阵的运算Chap.III 矩阵维数和类型的更改Chap.IV 矩阵最值统计 Refer…

可视化大屏的应用(11):智慧运维领域的得力助手

一、什么是智慧运维 智慧运维&#xff08;Smart Operations and Maintenance&#xff0c;简称智慧运维&#xff09;是一种利用先进的信息技术和数据分析手段&#xff0c;对设备、设施或系统进行监测、分析和优化管理的运维方式。它通过实时监测数据、智能分析和预测&#xff0…