【Linux】关于进程的理解、状态、优先级和进程切换

news2024/12/23 20:35:14

文章目录

    • 📝一、操作系统进程
      • 1.运行队列
      • 2.运行状态
    • 📝二、Linux进程状态
    • 📝三、两个特殊进程
      • 1.僵尸进程
      • 2.孤儿进程
    • 📝四、进程优先级
      • 1.优先级概念
      • 2.查看系统进程
      • 3.PRI和NI
      • 4.top命令更改nice
      • 5.特性
    • 📝五、进程切换
      • 1.并发
      • 2.进程如何切换
          • 📄时间片引出

📝一、操作系统进程

进程不同的状态本质都是在满足不同的运行场景的

1.运行队列

  • 运行队列

进程如何在CPU上运行的:CPU在内核上维护了一个运行队列,进行进程的管理。让进程入队列,本质就是将该进程的task_struct 结构体对象放入运行队列之中。

2.运行状态

  • 运行状态

进程PCB在运行队列里就是运行状态,不是说这个进程正在运行,才是运行状态。

状态是进程内部的属性,所有的属性在PCB里

进程不只是意味着占用CPU资源,也有可能随时要外设资源

  • 阻塞状态

进程不在运行队列之中,进程不能直接被调度,而是在等待外设资源的状态。本质是对tack_struct对象放到不同的队列中!

综上,所谓的进程不同的状态,本质是进程在不同的队列之中,等待某种资源

  • 挂起状态

如果系统中存在许多进程,进程短期内不会被调度,代码和数据在短期内不会被执行,此时如果内存空间不足,操作系统就可以把代码和数据暂时保存到磁盘上,节省一部分空间,该进程暂时被挂起了,这就是挂起状态。

对于阻塞状态和挂起状态,阻塞不一定挂起,挂起一定是阻塞

这些都是概念性的,对于Linux下具体的又是什么样子的呢👇


📝二、Linux进程状态

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

/*
* 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) 、D磁盘休眠状态(Disk sleep) 、T停止状态(stopped) 、X死亡状态(dead)

我们来一起看看Linux下运行状态(R)的样子:

image-20221106001411809

创建myprocess.c:

image-20221106001429115

image-20221106001200735

修改一下:

image-20221106001602908

image-20221106001733184

这是因为printf需要去访问外设显示器,外设比较慢,需要等待花时间(相对于CPU而言)。

我们可以来看看T状态

image-20221106120848698

而对于S来说是浅度睡眠,可以被终止,D是深度睡眠,无法被OS杀掉,只能通过断电、自己醒来进行解决。这里简单了解一下即可。

t状态:

image-20221109214226435

这也是一种暂停状态,tracing stop表示该进程正在被追踪


📝三、两个特殊进程

进程退出的时候不能立即释放该进程对应的资源!保存一段时间,让对应的父进程/操作系统进行读取

1.僵尸进程

僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程

下面,我们可以通过具体的例子来看一看僵尸进程,进程退出,但是没有被回收(父进程、OS)。我们可以通过创建一个子进程,让父进程不退出,让子进程正常退出(exit(1)):

image-20221109225943797

监控脚本命令:

while :; do ps axj | head -1 && ps axj | grep myprocess | grep -v grep; sleep 1; done

image-20221109231634937

右侧运行一段时间后出现Z状态:

image-20221109231754781

defunct的意思是失效的,也就是进程是已经死亡的,但是没有被回收。把左侧终止,在执行上面监视的命令,就不存在上面的进程了,这是因为把父子进程都终止的时候,操作系统自动回收了

image-20221109232325299

这就是僵尸进程。内存泄漏不仅仅只体现在malloc\new上,在系统中也会存在。

僵尸进程的危害

进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。父进程如果一直不读取,那子进程就一直处于Z状态
维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说, Z状态一直不退出, PCB一直都要维护
那一个父进程创建了很多子进程,就是不回收,就会造成内存资源的浪费,因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间

2.孤儿进程

父进程先退出,子进程就称之为“孤儿进程”

孤儿进程被1号init进程领养,由init进程回收。

话不多说,我们直接通过一小段代码来看一看:

image-20221109235121461

先来看一看z状态(杀掉子进程):

image-20221111083752869

现在重新启动进程(杀掉父进程):

image-20221111084248656

父进程结束掉没有看到它的僵尸状态:父进程也有父进程,都是bash的子进程,所以bash这个进程把父进程的资源回收了

image-20221111084728120

此时的30418变成1了:1就是对应的操作系统。子进程被1号领养的就是孤儿进程。

父进程先退出的现象是一定存在的,子进程会被操作系统领养(1号进程),这是为了回收子进程退出的时候对应的僵尸,管理子进程

被领养的进程就是孤儿进程。

image-20221111085235791

同时,子进程以前的状态是S+,现在变成了S,如果前台进程创建的子进程,如果变成孤儿会自动变成后台(此时用ctrl+C杀不掉,只能用kill解决)

image-20221111085827532


📝四、进程优先级

1.优先级概念

  • 优先级

对于优先级的理解,决定的是对于获取资源的先后顺序的能力。优先级高的先获得,优先级低的反之

存在的原因:资源太少,需要进行分配

cpu资源分配的先后顺序,就是指进程的优先权(priority)。

优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。

  • Linux优先级

优先级本质就是pcb里面的一个/几个整数数字

2.查看系统进程

在linux或者unix系统中,用ps –la命令则会类似输出以下几个内容 :

image-20221109190746763

UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行(就像成绩排名一样,越小越好)
NI :代表这个进程的nice值

3.PRI和NI

在Linux中由两个整数确定优先级:PRI(priority)和NI(nice)

在Linux下可以认为最终的优先级= 老的优先级+NI

注意:Linux下老的优先级默认值为80!而NI也就是nice值也有取值范围。取值范围是[-20,19],也就意味着优先级是有取值范围的[80-21,80+19]对于nice值的取值范围我们后面会做演示

在Linux下支持进程在运行中进行优先级调整的,调整的策略就是更改nice完成的,也就是说会受到nice值影响(但是一般情况下不修改)

但是大部分情况下,nice值是默认的也就是0:

image-20221109150904318

image-20221109150437211

这里的PRI优先级是80,下面我们可以对其进行更改

4.top命令更改nice

步骤1:sudo top

步骤2:进入top后输入r然后在输入进程的pid(进入进程)输入要修改nice的值

image-20221109151156968

image-20221109183003773

这里还是80,下面开始用top对其进行更改(输入sudo top然后在输入r):

image-20221109183048484

image-20221109183208442

  • 开始修改值

在输入要修改的值,这里以-100为例子,出现以下情况(最终变成-20):

image-20221109183627209

这里在修改成100,出现以下情况(最终变成19):

image-20221109183951376

注意:调优先级并不意味着你可以随便调,这是操作系统不允许的,会导致调度失衡。所以有着一定的取值范围

nice的取值范围是[-20,19],一共40个数字

如上就是Linux优先级的内容,这里简单了解一下。

5.特性

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

这里的独立性对于父进程和子进程是否还是存在?yes

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        while(1)
        {
            printf("this is child process,pid: %d,ppid:%d\n",getpid(),getppid());
            sleep(1);
            int *p = NULL;
            *p = 100;//野指针                                                           
         }
     }
    else
    {
        while(1)
          {
              printf("this is parent process,pid:%d,ppid:%d\n",getpid(),getppid());
              sleep(1);
          }
    }
}

image-20221109211938883

image-20221111095307832

子进程崩溃并没有影响父进程


📝五、进程切换

1.并发

多进程在同一CPU下通过采用进程不断切换的方式让一个单CPU计算机在一个时间段内同时让多个进程代码同时推进的现象称为并发

采用进程切换的方式在一个时间段内不同的进程都可以把代码跑起来,同时推进

2.进程如何切换

一个CPU里面存在一套硬件寄存器,宏观上寄存器分为用户可见,用户不可见

计算机调度某个进程时,CPU会把这个进程的PCB地址加载到某个寄存器,也就是说,CPU内有寄存器可以只找到进程的PCB地址

CPU里有一个eip寄存器(PC指针),指向当前执行指令的下一条指令的地址。

而进程运行的时候一定会产生很多的临时数据,但这些临时数据只属于当前进程,虽然CPU内部只有一套寄存器硬件,但是寄存器保存的数据只属于当前进程,也就是说,寄存器硬件不是寄存器内的数据,这是两码事,寄存器被所有进程共享,但是寄存器里的数据时每个进程各自私有的。

📄时间片引出

进程在运行的时候占有CPU,但是却不是一直占有到进程结束,进程都有自己的时间片!因为时间片的存在,进程会出现没有被执行完就被拿下去的情况,这时候问题来了:这个进程下一次如何在次回到CPU继续运行:

进程切换的时候,需要先进行上下文保护,这里的上下文指的是CPU里的寄存器的数据,而不是寄存器,这里简单理解为临时数据保存至PCB里,而当进程恢复运行的时候,要进行上下文的恢复,该进程在次回到CPU继续运行时,重新加载恢复这些数据。

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

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

相关文章

软件工程方法论

🐰作者简介:一位普通高校的在校学生,致力于提高自己的编程能力。 🍌个人主页:比昨天强一點的博客_CSDN博客-C语言从0到精通领域博主 🍍系列专栏:C语言从0到精通_比昨天强一點的博客-CSDN博客 &a…

真良心干货保姆级手把手教你Python网络编程,学不会我去你家教你

Python网络编程基本概念(计算机网络基础)IP地址与端口IP地址端口网络通信协议网络通信协议网络协议的分层TCP/UDP套接字编程socket()函数介绍UDP 编程实现UDP发送数据实现UDP先发送数据再接收数据实现UDP实现多线程聊天TFTP文件下载器基本概念下载的过程python内置模块structTC…

C/C++ Qt 标准Dialog对话框组件应用

在Qt中对话框分为两种形式,一种是标准对话框,另一种则是自定义对话框,在一般开发过程中标准对话框使用是最多的了,标准对话框一般包括 QMessageBox,QInputDialog,QFileDialog 这几种,这里我将总结本人在开发过程中常用…

蓝桥杯——2022年11月第十四届蓝桥杯模拟赛第一期Java

1、二进制位数 问题描述 十进制整数 2 在十进制中是 1 位数,在二进制中对应 10 ,是 2 位数。 十进制整数 22 在十进制中是 2 位数,在二进制中对应 10110 ,是 5 位数。 请问十进制整数 2022 在二进制中是几位数? 答案…

C++学习之旅 第二章 printf与cout

目录 1.printf简介 2.printf的四种用法 2.1 printf("字符串"); 2.2 printf("输出控制符",输出参数); 2.3 printf("输出控制符1 输出控制符2 ,,,,,,,, ", 输出参数1, 输出参数2,....... ); 2.4 printf("输出控制…

化妆品展示网页设计作业 静态HTML化妆品网站 DW美妆网站模板下载 大学生简单网页作品代码 个人网页制作 学生个人网页设计作业

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

C++11【智能指针详解】

智能指针🏞️1. 为什么引入智能指针?🌁2. 智能指针的使用及原理📖2.1 RAII思想📖2.2 智能指针的原理🌠3. 常见智能指针📖3.1 auto_ptr📖3.2 unique_ptr📖3.3 shared_ptr&…

基于深度学习的宋词生成

《自然语言处理》课程报告 摘 要 宋词是一种相对于古体诗的新体诗歌之一,为宋代儒客文人智慧精华,标志宋代文学的最高成就。宋词生成属于自然语言处理领域的文本生成模块,当前文本生成领域主要包括基于语言模型的自然语言生成和使用深度学习…

RK3568平台开发系列讲解(安卓适配篇)Android 源码的 device 目录

🚀返回专栏总目录 文章目录 一、device 目录简介二、Android 产品配置各种变量沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 Android 源码的 device 目录。 一、device 目录简介 Android 源码下的 device 目录是 Android 源码中对产品的描述文件夹,各…

STM32个人笔记-CAN总线通讯

笔记来源于STM32F103VET6,野火指南者,中文参考手册,HAL库开发手册和b站的野火指南者视频。观看过好多次了,但往往理解得不够全面,现记下小笔记,用来回顾。属于个人笔记。​​​​​ 大四实习那年记忆颇深…

基于Java+Springboot+Vue+elememt宠物用品商城系统设计实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取联系🍅精彩专栏推荐订阅👇&#x1f…

K线形态识别_空方尖兵

写在前面: 1. 本文中提到的“K线形态查看工具”的具体使用操作请查看该博文; 2. K线形体所处背景,诸如处在上升趋势、下降趋势、盘整等,背景内容在K线形态策略代码中没有体现; 3. 文中知识内容来自书籍《K线技术分析》…

第九章 内置模块

目录 第九章 内置模块 1.math模块 1.查看: 2.常用方法: 2.random模块 1.查看: ​2.例: 3.random(a,b) 4.random.sample(range(0,20),10) 3.os模块与os.path模块 1.作用 2.目录 3.os模块与操作系统的关系 4.路径 5.判…

自我实现tcmalloc的项目简化版本

项目介绍 该项目是基于现代多核多线程的开发环境和谷歌项目原型tcmalloc的自我实现的简化版本,相比于本身就比较优秀的malloc来说,能够略胜一筹,因为其考虑了 性能,多线程环境,锁竞争和内存碎片的问题,主要利用了池化思想来管理内存分配,对于每个线程,都有自己的私…

鸿蒙开发套件全面升级,助力鸿蒙生态蓬勃发展

目录 1. 全场景分布式系统 2. HarmonyOS的超能力:ArkTS API万箭齐发 3.解锁“鸿蒙开发套件”的新技能 (1) 智能代码编辑器 (2)Hvigor编译构建 (3)热重载:向看直播一样查看运行…

MySQL : 彻底搞懂一条SQL的执行过程

整体流程 组件介绍 连接器 处理客户端的连接,一般处理我们这个命令,判断是否满足接入server的条件 mysql ‐h host[数据库地址] ‐u root[用户] ‐p root[密码] ‐P root查询缓存 在8.0之前,如果用户开启了查询缓存的开关,那么…

vue2.6 + ts 使用vuex

目录vue2.6 ts 使用vuex安装01:直接使用 store / index.ts的数据store / index.tsmain.ts001:同步mutation操作vuex数据与获取getters001:效果002:异步action、mutation操作vuex数据002:效果02:引入其他模…

CANoe 简介

🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】🍅 玩转CANoe&…

Go 语言项目源码解析:定时任务库 cron

环境准备 首先我们将源码克隆(Fork)为自己的个人仓库,只需要在 GitHub 项目主页点击 Fork 按钮,然后输入项目名称点击确认即可。克隆完毕后,可以下载到本地,或者直接在科隆后的 GitHub 仓库主页上点击 Cre…

RabbitMQ

RabbitMQ 1.MQ引言 MessageQueue: 消息队列 模块之间的耦合度多高,导致一个模块宕机后,全部功能都不能用了,并且同步通讯的成本过高,用户体验差。 1.1什么是MQ MQ(Message Queue)消息队列,是基…