【Linux】进程优先级与进程切换理解

🌟🌟作者主页:ephemerals__

🌟🌟所属专栏:Linux

目录

前言

一、进程优先级

1. 什么是进程优先级

2. 为什么有进程优先级

3. 进程优先级的作用

4. Linux进程优先级的本质

5. 修改进程优先级

二、进程切换

1. 概念 

2. 进程切换的过程

3. 进程切换的意义

4. Linux的进程调度(O(1)调度算法)

总结


前言

        本篇文章我们在了解了进程概念和状态等基础知识之上,继续学习进程的优先级,以及进程切换相关知识。

正文开始

一、进程优先级

1. 什么是进程优先级

        进程优先级是操作系统分配给进程的一种“权重”或“级别”,用来决定在多个进程同时竞争 CPU 资源时,哪一个进程先获得运行的机会。优先级高的进程会被优先调度执行,低优先级的进程则可能需要等待。 

2. 为什么有进程优先级

        大多数情况下,正在执行的程序数量是比较多的,而CPU资源有限为了使那些重要、急需执行的任务先执行,就有了优先级。这样一来,资源分配会得到优化,整个系统更加合理高效。

注:现代操作系统更加考虑进程获取资源的公平性,优先级的差距不会太大。

3. 进程优先级的作用

        进程优先级可以保证关键任务或实时任务及时调度(如操作系统内核进程通常优先级较高),并且可以防止某个进程长期占用 CPU,改善系统性能。其次,优先级可以实现多用户或多任务下的公平资源分配

4. Linux进程优先级的本质

        在Linux下,进程优先级的本质就是一个整数,存储在task_struct结构体当中,直接影响了进程调度的先后顺序。进程优先级的值越小,优先级越高

可以使用以下命令查看到当前所有进程的优先级:

ps -al

运行结果:

PRI:进程优先级的值,默认是80

NI:也叫做nice值,是进程优先级的修正数据。其取值范围是[-20, 19]

PRI的默认值(80) 和 NI 之和表示进程的真实优先级大小。也就是说,Linux进程优先级的范围是[60, 99],一共40个。

注:ps -l指令还可以看到当前进程的PID,父进程ID等。其中还有一项UID,它用来标识Linux下的用户,进行用户区分。当用户创建进程时,进程会记录用户的UID,访问文件时(本质是进程在访问),进程就拿这个UID与文件的拥有者或所属组的UID进行对比。

5. 修改进程优先级

        在Linux下,修改进程优先级主要是通过修改nice值来完成(注意nice值的取值范围)。可以使用top命令修改进程优先级:

输入top --> 按“ r ” --> 输入进程的PID --> 输入新的nice值

注意:普通用户只能给自己的进程设置优先级,且只能将优先级调低(nice值调高);而root用户可以在取值范围内随意调整任意进程的优先级。 

 接下来我们尝试调整一个进程process的优先级:

process的源码:

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

首先运行process,查看process的优先级:

可以看到process的优先级是80。接下来将nice修改为10:

这里process的PRI变成了90,而nice值为10。此时90是process的真实优先级。 

如果修改为-10:

可以看到,普通用户下,将nice值调低是不被允许的。

如果改为100:

由于取值范围的限制,nice值最高为19,输入100只能将其改为19。

注意:如果优先级设置不合理,就会导致优先级低的进程长时间获取不到CPU资源,导致进程饥饿。

二、进程切换

1. 概念 

        CPU在执行一个进程时,由于还有其他进程的存在,它不会一次将所有代码全部跑完,而是跑一会后,转而去执行其他进程,再来执行当前进程......这样才可以在一段时间之内使得多个进程都有所推进。CPU从执行当前进程变为执行其他进程的过程叫做进程切换

当代操作系统都是分时的,每个进程都有它相应的时间片(本质就是一个计时器)。当前进程的时间片用完后,就会切换到其他进程。

2. 进程切换的过程

        一个进程在CPU上运行到时间片结束之后,首先存储自己执行位置的上下文数据到自己的TSS(任务状态段,存储在task_struct当中)当中,然后将进程重新放入调度队列队尾。进程发生切换时,将新的进程的TSS中的数据拷贝(恢复)到CPU的对应寄存器中,继续执行。 

进程的上下文数据指的是进程在运行时,需要保存和恢复的所有关键信息(例如发生切换时CPU寄存器中的数据),这样就可以保证进程发生一系列切换后,重新执行该进程时,能从原来的状态继续执行。

3. 进程切换的意义

        进程切换让操作系统能管理多个进程,保证各进程能按照优先级获得CPU使用权,是实现多任务的基础。多个进程可以“轮流”运行,系统利用率和响应速度得以提高。

4. Linux的进程调度(O(1)调度算法)

        高效的进程切换不仅保证了多任务系统的流畅运行,还直接影响着系统的响应速度与整体性能。为了实现快速、合理的进程调度,Linux内核采用了多种调度算法,其中O(1)调度器就是在2.6版本中所引入的一种重要算法。接下来,我们将深入了解O(1)调度算法,看看它是如何实现对大量进程的高效管理的。

        在之前的文章中,我们提到过一个CPU维护一个进程调度队列,该队列中存放着一个个PCB,等待CPU对它们进行调度。实际上这个“进程调度队列”远远比传统的队列复杂。在Linux中,进程调度队列叫做runqueue,它的结构如图所示:

一个CPU维护一个运行队列runqueue,其中数组prio_array_t中的queue是存放进程PCB的关键。

queue本质是一个链地址法的哈希表,其中有140个哈希桶(前100个哈希桶表示实时优先级,剩余40个刚好对应40种优先级,所以哈希桶的下标 - 40就是进程优先级),相同优先级的进程task_struct存放在同一个哈希桶中,这样,当需要调度时,按照下标小到大的顺序扫描每一个哈希桶,先访问到的进程就是优先级高的(因为优先级的值越小,优先级越高),然后拿出桶中的task_struct进行调度。

考虑到每次都要遍历140个哈希桶,效率较低,所以有一个位图bitmap,位图中有5个32位的整形变量,加起来一共160位,其中的140位表示对应的哈希桶中是否有task_struct,所以可以直接判断哪一位是“1”,就表示哪一个桶需要被访问。除此之外,还有一个变量nr_active,表示整个哈希表中的元素个数,对应正在运行时的进程个数。

queuebitmapnr_active共同构成一个结构体,叫做rqueue_elem。

如此,访问位图,按顺序找到存在元素的哈希桶,进行调度,整个调度过程效率就能达到O(1)。 

但是图中的prio_array_t数组有两个元素,也就是说有两张哈希表,这是为什么呢?这就要从进程切换的角度开始谈起了。

试想,如果只有一张哈希表,那么发生进程切换时会怎么样?

假设第100个哈希桶当中有3个进程,第一个进程的时间片耗尽后,会发生进程切换,此时按照优先级,只能将它重新插入在当前哈希桶的链表尾部,当然,其他两个进程也是如此。这样虽然能够完成这3个进程的轮流调度,但是更低优先级(也就是下标更大的哈希桶)的进程呢?当前哈希桶中只要有元素,CPU就会一直轮流调度当前哈希桶中的进程,而会忽略优先级更低的进程,导致进程饥饿。要调度优先级更低的进程,就必须等待当前优先级的进程全部调度完毕,显然是不合理的,极大地损失了公平性

因此,前辈们想到了一个巧妙的方法:再创建一个相同的结构体rqueue_elem,其中也包含一个queuebitmapnr_active,两个rqueue_elem构成一个数组prio_array_t[2]

然后创建两个指针nativeexpired,分别指向prio_array_t[0]和prio_array_t[1],native指向的表示“活跃队列”;expired指向的表示“过期队列”。当发生进程切换时,被调度结束的进程会插入到“过期队列”的对应优先级的哈希桶中,然后继续访问“活跃队列”中的哈希桶,一个个地调度。这样,当前“活跃队列”哈希桶中的元素就会越来越少,直到为0,就可以访问优先级更低的哈希桶......最后所有进程都会被调度,而不是高优先级进程运行完毕后才能调度低优先级进程。

当“活跃队列”整个哈希表内的进程都被调度过后(此时这些进程应全都位于“过期队列”对应的哈希桶中),交换native和expired两个指针的指向,这样“过期队列”就变成了“活跃队列”,就可以开始下一轮的调度了。

如果有新进程出现,会直接插入“过期队列”当中。此时新进程处于“就绪状态”,等待一轮的调度结束后,新进程就可以被调度。

总结

        本篇文章,我们系统地了解了进程优先级的定义、意义以及在Linux下的调整方法,也梳理了进程切换的基本流程与核心作用。从进程优先级到切换机制,再到Linux的O(1)调度算法,这些知识共同揭示了操作系统在多任务管理中的高效与精妙。掌握这些原理,有助于更深入理解和优化 Linux 系统的性能,为后续程序地址空间进程控制的学习打下坚实基础。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤

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

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

相关文章

【Hive入门】Hive高级特性:事务表与ACID特性详解

目录 1 Hive事务概述 2 ACID特性详解 3 Hive事务表的配置与启用 3.1 启用Hive事务支持 3.2 创建事务表 4 Hive事务操作流程 5 并发控制与隔离级别 5.1 Hive的锁机制 5.2 隔离级别 6 Hive事务的限制与优化 6.1 主要限制 6.2 性能优化建议 7 事务表操作示例 7.1 基本…

二叉树算法精解(Java 实现):从遍历到高阶应用

引言 二叉树&#xff08;Binary Tree&#xff09;作为算法领域的核心数据结构&#xff0c;在搜索、排序、数据库索引、编译器语法树构建等众多场景中都有着广泛应用。无论是初学者夯实算法基础&#xff0c;还是求职者备战技术面试&#xff0c;掌握二叉树相关算法都是不可或缺的…

ES6入门---第二单元 模块二:关于数组新增

一、扩展运算符。。。 1、可以把ul li转变为数组 <script>window.onloadfunction (){let aLi document.querySelectorAll(ul li);let arrLi [...aLi];arrLi.pop();arrLi.push(asfasdf);console.log(arrLi);};</script> </head> <body><ul><…

Nature正刊:新型折纸启发手性超材料,实现多模式独立驱动,变形超50%!

机械超材料是一种结构化的宏观结构&#xff0c;其几何排列方式具有独特的几何结构&#xff0c;从而具有独特的力学性能和变形模式。超材料的宏观特性取决于中观尺度晶胞的具体形状、尺寸和几何取向。经典的结构化晶胞&#xff0c;例如以拉伸为主的八面体桁架单元和以弯曲为主的…

Servlet(二)

软件架构 1. C/S 客户端/服务器端 2. B/S 浏览器/服务器端&#xff1a; 客户端零维护&#xff0c;开发快 资源分类 1. 静态资源 所有用户看到相同的部分&#xff0c;如&#xff1a;html,css,js 2. 动态资源 用户访问相同资源后得到的结果可能不一致&#xff0c;如&#xff1a;s…

循环缓冲区

# 循环缓冲区 说明 所谓消费&#xff0c;就是数据读取并删除。 循环缓冲区这个数据结构与生产者-消费者问题高度适配。 生产者-产生数据&#xff0c;消费者-处理数据&#xff0c;二者速度不一致&#xff0c;因此需要循环缓冲区。 显然&#xff0c;产生的数据要追加到循环缓…

嵌入式硬件篇---STM32 系列单片机型号命名规则

文章目录 前言一、STM32 型号命名规则二、具体型号解析1. STM32F103C8T6F103:C:8:T6:典型应用2. STM32F103RCT6F103:R:C:T6:典型应用三、命名规则扩展1. 引脚数与封装代码2. Flash 容量代码3. 温度范围代码四、快速识别技巧性能定位:F1/F4后缀差异硬件设计参考:引脚数…

MySQL 中日期相减的完整指南

MySQL 中日期相减的完整指南 在 MySQL 中&#xff0c;日期相减有几种不同的方法&#xff0c;具体取决于你想要得到的结果类型&#xff08;天数差、时间差等&#xff09;。 1. 使用 DATEDIFF() 函数&#xff08;返回天数差&#xff09; SELECT DATEDIFF(2023-05-15, 2023-05-…

传奇各版本迭代时间及内容变化,屠龙/嗜魂法杖/逍遥扇第一次出现的时间和版本

​【早期经典版本】 1.10 三英雄传说&#xff1a;2001 年 9 月 28 日热血传奇正式开启公测&#xff0c;这是传奇的第一个版本。游戏中白天与黑夜和现实同步&#xff0c;升级慢&#xff0c;怪物爆率低&#xff0c;玩家需要靠捡垃圾卖金币维持游戏开销&#xff0c;遇到高级别法师…

重塑数学边界:人工智能如何引领数学研究的新纪元

目录 一、人工智能如何重新定义数学研究的边界 &#xff08;一&#xff09;数学与AI的关系&#xff1a;从基础理论到创新思维的回馈 &#xff08;二&#xff09;AI的创造力&#xff1a;突破传统推理的局限 &#xff08;三&#xff09;AI对数学研究的潜在贡献&#xff1a;创…

IP伪装、代理池与分布式爬虫

一、动态代理IP应用&#xff1a;代理池的获取、选择与使用 代理池技术的核心是通过动态切换IP地址&#xff0c;让爬虫看起来像不同用户在访问网站&#xff0c;从而规避封禁。 &#xff08;一&#xff09;代理池的获取途径 1. 免费代理&#xff1a;低成本但高风险 免费代理可…

自然语言处理实战:用CRF打造高精度命名实体识别系统

## 一、从标签游戏到智能系统:命名实体识别的前世今生 在信息爆炸的互联网时代,我们每天面对的海量文本中隐藏着无数有价值的信息。想象一下,当你在浏览新闻时,系统能自动标红所有人名、地点和机构名称——这就是命名实体识别(NER)技术的魔力。从早期的规则匹配到如今的…

Space Engineers 太空工程师 [DLC 解锁] [Steam] [Windows]

Space Engineers 太空工程师 [DLC 解锁] [Steam] [Windows] 需要有游戏正版基础本体&#xff0c;安装路径不能带有中文&#xff0c;或其它非常规拉丁字符&#xff1b; DLC 版本 至最新全部 DLC 后续可能无法及时更新文章&#xff0c;具体最新版本见下载文件说明 DLC 解锁列表&…

JVM——JVM 是如何执行方法调用的?

JVM 是如何执行方法调用的&#xff1f; 在 Java 世界的底层运作中&#xff0c;方法调用机制是理解 Java 虚拟机&#xff08;JVM&#xff09;行为的关键之一。JVM 作为 Java 程序运行的核心&#xff0c;承担着执行字节码、管理内存、调度线程等多项职责。而方法调用作为程序逻辑…

MySQL 数据类型详解:字符串、数字、日期

MySQL 数据类型详解&#xff1a;字符串、数字、日期 在 MySQL 中&#xff0c;选择合适的数据类型对于数据库的存储效率和查询性能至关重要。MySQL 提供了**字符串&#xff08;String&#xff09;、数字&#xff08;Numeric&#xff09;和日期&#xff08;Date & Time&…

题解:P2485 [SDOI2011] 计算器

### 思路 本题是一个比较模板化的题目。 #### 一操作 考虑使用快速幂。 快速幂&#xff0c;只需要把 $k$ 变成二进制即可实现 $\Theta(\log k)$ 的时间复杂度。 实现方法&#xff1a; cpp long long qmi(long long a,long long k,long long p){ long long res 1; …

重新构想E-E-A-T:提升销售与搜索可见性的SEO策略

在2025年的数字营销环境中&#xff0c;谷歌的E-E-A-T&#xff08;经验、专业性、权威性、可信度&#xff09;已成为SEO和内容营销的核心支柱。传统的E-E-A-T优化方法通常聚焦于展示作者资质或获取反向链接&#xff0c;但这些策略可能不足以应对AI驱动的搜索和日益挑剔的用户需求…

JVM 一文详解

目录 JVM 简介 JVM 中的内存区域划分 1. 堆&#xff08;一个进程只有一份 ------ 线程共享&#xff09; 2. 栈&#xff08;一个进程可以有 N 份 ------ 线程私有&#xff09; Java 虚拟机栈&#xff1a; 本机方法栈&#xff1a; 3. 程序计数器&#xff08;一个线程可以…

小程序与快应用:中国移动互联网的渐进式革命——卓伊凡的技术演进观

小程序与快应用&#xff1a;中国移动互联网的渐进式革命——卓伊凡的技术演进观 在知乎看到很多&#xff1a;“懂王”发布的要把内行笑疯了的评论&#xff0c;卓伊凡必须怼一下&#xff0c;真印证那句话&#xff0c;无知者无畏 一、Web与小程序的技术本质差异 1.1 浏览器渲染…

[SC]SystemC在GPU/CPU SoC验证中的应用案例

SystemC在GPU/CPU SoC验证中的应用案例 摘要:SystemC 是一种基于 C++ 的系统级建模语言,广泛用于 SoC (System on Chip) 设计的建模和验证,尤其在 GPU SoC 验证中,SystemC 可用于模拟硬件模块、系统行为和性能评估。SystemC 的主要优势在于支持系统级抽象建模、时序…