【day12】进程切换与调度:linux系统的幕后操控术

【Day12】进程切换与调度:linux系统的幕后操控术

  • 进程优先级
    • 进程属性:UID
    • 进程属性:PRI和NI
    • 进程饥饿
  • 竞争/独立/并行/并发
  • 进程切换
  • 进程调度(O(1)调度算法)

进程优先级

进程优先级的本质:衡量进程得到CPU资源的先后顺序。

资源是相对有限的,特别是CPU资源,一个CPU一次只能跑一个进程,而进程可以有多个,所以需要存在进程优先级来确定进程获取CPU资源的先后顺序。以此保证os能合理地分配资源,确保各个进程之间的良性竞争。

优先级代表能得到资源,只不过是啥时候得到。权限指的是是否能得到某种资源。

优先级是进程的一种属性,在一般os内,进程优先级就是一个整数,值越低,表示优先级越高。

基于时间片的分时操作系统:把计算机的系统资源(尤其是CPU时间)进行时间上的分割,每个时间段称为一个时间片。分时操作系统把时间片轮流分配给进程使用,若某个进程在分配给它的时间片内没有完成其计算,则该进程暂时中断,把时间片让给另一进程使用,等待下一轮时再继续其运行。这样可以保证每个进程都能获得一定的时间片,同时高优先级的进程可能获得更多时间片或更频繁的调度。

每个进程都有他合适的时间片(其实就是一个计算器),时间⽚到达,进程就被操作系统从CPU中剥离下来。

linux就是基于时间片的分时操作系统。

进程属性:UID

linux是多用户操作系统,一个进程由是哪个用户启动的,表现在进程的UID属性上,UID即userId。
在这里插入图片描述
用户访问文件需要权限,os怎么知道访问文件的用户,是文件的拥有者,所属组,还是other呢?
linux系统中,访问任何资源,都是进程访问,进程就代表用户。所以用户访问文件,本质上就是进程访问文件,代表用户的进程UID和文件拥有者/所属组/other一对比,os就知道要操作该文件用户的身份了。

进程属性:PRI和NI

PRI是进程的优先级,默认值是80;NI是进程优先级的修正数据,默认为0。
在这里插入图片描述
进程真实的优先级=PRI(80)+NI。每次修改进程优先级,都是在PRI的默认值80的基础上再加上新设置的NI值

通过nice,renice,top命令都可以调整进程优先级,通过一些系统调用接口也能调。
例如,用top命令调整进程优先级:
创建myprocess.c文件:
在这里插入图片描述编译运行myprocess程序:
在这里插入图片描述

运行 top 命令,然后按“r”,输入要调整进程的 PID 编号并按回车。
根据提示,重置 NICE 值。例如:Renice PID [具体PID] to value : [新的NICE值]。
按 q 退出 top 模式,然后使用 top -p [PID编号] 只查询某个进程的信息。
其中NI的取值范围是[-20,19]。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

进程饥饿

在操作系统中,进程饥饿(Process Starvation) 指某些进程因资源分配策略或调度算法的不公平性,长时间无法获得所需的系统资源(如CPU时间、内存、I/O等),导致其无法正常执行的现象。

NI的取值范围是[-20,19],所以linux进程的优先级范围是[60,99],一共40个级别。linux中进程优先级的级别并不是很多,这是为了在进程竞争资源时,保证资源分配的公平性。如果优先级级别过多,就可能会导致优先级低的进程长时间得不到CPU资源,进而导致“进程饥饿”。

竞争/独立/并行/并发

竞争:系统中的资源,相比于进程的数量来说,永远是不够的,所以在进程之间,必然存在竞争资源的情况。为了高效完成任务,更合理竞争相关资源,便具有了优先级和权限。

独立:进程=内核数据结构(比如task_struct)+自己对应的代码和数据。每个进程在运行的时候,都认为自己独占系统资源。例如,在计算机中可以同时运行多个程序,如一边挂着QQ,一边挂着微信,另一边用腾讯会议来上课。每个程序运行时可能会产生多个进程,这些进程在客户端是相互独立的,一个进程出现问题(除导致系统崩溃的情况外)不会影响其他进程。这就是进程的独立性。

并行:若干个进程同时在系统中运行,这些进程的执行在时间上是重叠的,比如在一个双CPU的计算机上同时运行两个进程,其中每个CPU上分别运行一个进程。

并发:在一个单核CPU的计算机上同时运行多个进程,一个cpu同一个时间只能处理一个进程,所以CPU处理这些进程的时候,采用进程切换的方式,不断交替执行多个进程,在一段时间内,让多个进程都得以推进,称为并发。进程的运行实际上是一卡一卡的。

进程切换

死循环进程如何运行:

一旦一个进程占有CPU,不会直接把自己的代码跑完(除非代码很短)!每个进程在时间片上跑一段代码就会被os剥离下来,让后面的进程上去跑。所以死循环进程不会卡死系统,因为它不可能一直占有CPU。

CPU选择一个进程执行的时候,会直接访问进程的代码和数据。CPU内有很多寄存器,寄存器是CPU内部的高速存储单元(CPU内部的临时空间),它们能够快速存储和处理数据,提高计算机的性能和运行速度。

一部分寄存器用于保存正在运行的进程的临时数据。
寄存器是CPU内部用来保存数据的空间,寄存器里面的内容是寄存器里保存的数据。空间只有一份,数据由于实际需求是会发生变化的。

进程切换指的是,操作系统把 CPU 上正在运行的进程切换成另一个进程。即把正在CPU上运行的进程从CPU上剥离下去,然后让下一个进程到CPU上执行的过程。

实现进程切换的关键是保存和恢复当前进程的上下文数据,进程的上下文数据指的是进程运行时的临时数据,进程运行时,其上下文数据通常保存在CPU寄存器中。

进程到CPU上运行,要先在CPU上恢复它的上下文数据,进程开始运行,进程从CPU上剥离前,要先保存它的上下文数据,然后剥离。

进程剥离前要保存它的上下文数据,以保证下一次再运行时能恢复,进程被切换离开CPU前,它的上下文数据会被保存到task_struct中,即把寄存器中的运行临时数据拷贝到内存中。

在旧linux内核中,上下文数据保存在task_struct中,但后来随着时代发展,在新linux内核中,把上下文数据独立出来保存了。
旧linux中保存上下文数据:
在这里插入图片描述
在这里插入图片描述
如果进程是第一次到CPU上运行,不需要恢复上下文数据。在task_struct中设置一个变量做标记位,进程没执行过标记位位0,到CPU上执行过以后,标记位变成1。这样linux就知道了。

进程切换的速度非常快,所以在用户看来,就像多个进程同时运行一样。

进程调度(O(1)调度算法)

不同os采用的调度算法有所不同,linux内核中采用过的经典的调度算法是O(1)调度算法。如下:

调度和切换共同构成调度器。

每个CPU都对应一个运行队列runqueue,
如下是Linux2.6内核中运行队列的数据结构:
在这里插入图片描述在runqueue中,queue指向一个140大小的数组。其中下标[0,99]范围内的空间,是linux为实时优先级设置的,这里不细说。下标[100,139]范围内的空间是linux为分时优先级设置的。

进程的PRI属性[60,99]和queue的[100,139]是对应的。
假设进程PRI是x,则对应在queue中下标是x-60+100
queue的[100,139]每个下标空间中保存的都是task_struct*,优先级相同的进程都会被链入到queue中对应下标空间中。queue中一个下标空间中的进程用队列组织,同时按照先进先出FIFO的方式被调度。
所以,queue数组的本质就是一个开散列的哈希表。

在这里插入图片描述

调度器按照进程优先级调度进程,意味着调度器要从queue[100]开始遍历queue中的每个task_struct*。

调度器如何在queue中快速的挑选一个进程?
bitmap[5]的类型是unsigned int,共160(32*5=160)个比特位,这160个比特位中的前140bit和queue的140个位置是对应的,(从左到右)第一个比特位对应queue[0]。比特位的内容是0/1,映射到queue中,代表对应的位置里是否存在进程。

这样一来,把调度器遍历queue转变成查找bitmap[5],时间复杂度从O(n)变成O(1)。

runqueue中nr_active表示的是整个queue中进程的总数量,所以调度器在选择进程的时候,先访问nr_active(>0),再查bitmap[5],再查queue,从而获得进程,进行切换。

当进程在CPU上执行一个时间片后,又被os从CPU上剥离下来了,此时,如果把这个剥离下来的进程继续放到之前的queue[140]中,根据上述获得进程的方法,和它优先级相同的进程被调度后,不久之后这个进程又会被调度,陷入循坏,而优先级在它后面的进程会发生进程饥饿。

所以,linux在runqueue中挑进程时,永远只从active指向的对象中挑,进程被从CPU上剥离下来以后,被放入 expired指向的对象中。在整个调度期间,active中的进程会越来越少,expired中的进程会越来越多,active中的进程全部被调度完以后(queue[140]中的进程也被调度完后),swap(&active,&expired),交换active和expired这两个指针类型变量中的内容,
然后重复调度。
在这里插入图片描述当有新进程来时,默认被放到expired指向的对象中,即进程的就绪状态。有的os支持内核优先级抢占,会把新进程放到active指向的对象中。

以上就是O(1)调度算法。

如果一台计算机是多CPU,进程调度的时候,会根据负载算法把进程分给合适的CPU,即系统内多CPU并行运行时,保证CPU的负载均衡。

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

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

相关文章

STM32之BKP

VBAT备用电源。接的时候和主电源共地,正极接在一起,中间连接一个100nf的电容。BKP是RAM存储器。 四组VDD都要接到3.3V的电源上,要使用备用电池,就把电池正极接到VBAT,负极跟主电源共地。 TEMPER引脚先加一个默认的上拉…

mapbox高阶,结合threejs(threebox)添加管道

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️threebox Tube静态对象二、🍀使用thr…

Android15使用FFmpeg解码并播放MP4视频完整示例

效果: 1.编译FFmpeg库: 下载FFmpeg-kit的源码并编译生成安装平台库 2.复制生成的FFmpeg库so文件与包含目录到自己的Android下 如果没有prebuiltLibs目录,创建一个,然后复制 包含目录只复制arm64-v8a下

利用FatJar彻底解决Jar包冲突(三)

利用FatJar彻底解决Jar包冲突 Spring 容器的加载与隔离⽀持注解配置⽂件定位与容器初始化嵌套Spring容器的加载 隔离优化EagleEye traceId不⼀致问题原因解决 Spring 容器的加载与隔离 ⽀持注解 这个⽐较容易,主要是我们之前的应⽤不⽀持⼆⽅包内部的注解&#xf…

ThinkPHP8.0+MySQL8.0搭建简单实用电子证书查询系统

客户花了100元买了一个系统,开始不能导入,到处找人帮忙解决。给解决能导入了,不能修改,满足不了用户的需求。用户一狠心,花200块钱,叫我给他定制了一个电子证书查询系统。还免费给部署到服务器。惭愧惭愧……

越早越好!8 个反直觉的金钱真相|金钱心理学

很多人都追求财富自由,但成功的人少之又少。 这可能是因为,人们往往忽略了一些金钱的真相和常识。 01 金钱常识 & 真相 为了构建健康的金钱观,我读了一本有点反直觉,有点像鸡汤,但都是财富真相的书。 来自 Morg…

文本转语音-音画适时推送rtsp并播放

文本语音 rtsp适时播放叫号系统的底层逻辑 发布Linux, unix socket 和window win32做为音频源的 python10下的(ffmpeg version 7.1) 可运行版本. 这两天在弄这个,前2篇是通过虚拟声卡,达到了最简单的一个逻辑,播放文本就从声卡发声&#xff0…

类和对象(中)

1.类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。默认成员函数:用户没有显式实现,编译器会生成…

搜索插入位置(js实现,LeetCode:35)

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2示例 2: 输入…

【问题记录】如何编译nv_peer_memory模块?依赖OFED的4个目录和2类文件?如何解决没有rdma/peer_mem.h文件?

背景 GDR:GPUDirect RDMA。这项新技术在 GPU 内存之间直接与 NVIDIA HCA/NIC 设备之间提供直接的 P2P(点对点)数据路径。这显着降低了 GPU-GPU 通信延迟,并完全减轻了 CPU 的负担。nv_peer_memory模块是网卡提供给GPU使用GDR技术…

3.6c语言

#define _CRT_SECURE_NO_WARNINGS #include <math.h> #include <stdio.h> int main() {int sum 0,i,j;for (j 1; j < 1000; j){sum 0;for (i 1; i < j; i){if (j % i 0){sum i;} }if (sum j){printf("%d是完数\n", j);}}return 0; }#de…

李彦宏:紧抓AI智能体爆发元年机遇 推动新质生产力加快发展

来源 人民网 3月5日公布的政府工作报告&#xff0c;“智能”一词被提及10次&#xff0c;“大模型”则首次被写入。作为大模型和人工智能领域的领军企业&#xff0c;我们感到非常振奋&#xff0c;同时深感责任重大。 报告在介绍今年政府工作任务时提出&#xff0c;“因地制宜发…

基于Python Django的人脸识别上课考勤系统(附源码,部署)

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

5G基本概念

作者:私语茶馆 1. 5G应用场景概述 1.1.5G应用场景 ITU域2015年定义了三大应用场景:eMBB(增强型移动宽带)、uRLLC(低时延高可靠通信)、mMTC(海量物联网通信); emBB:Enhanced Mobile Broadband ,移动互联网应用,是4G MBB(移动宽带)的升级,主要侧重于网络速率、带…

VSCode+AI编程生态实战:从环境配置到智能编码的全栈指南

Python环境的搭建&#xff0c;我们选择了Anaconda环境&#xff0c;有Python环境&#xff0c;接下来要搭建当然是AI辅助编程环境了。在搭建这个之前&#xff0c;或者说大家在打算安装VSCode之前&#xff0c;需要先检查自已电脑是否已经安装了VSCode&#xff0c;因为这个软件是Wi…

Ubuntu工控卫士在制造企业中的应用案例

在当今数字化时代&#xff0c;信息安全已成为各行各业关注的焦点。特别是在工业控制领域&#xff0c;网络安全Linux工控机&#xff08;简称“工控卫士”&#xff09;作为信息安全防护的核心设备&#xff0c;正发挥着越来越重要的作用。本文将深入探讨工控卫士在信息安全防护场景…

Stable Diffusion教程|快速入门SD绘画原理与安装

什么是Stable Diffusion&#xff0c;什么是炼丹师&#xff1f;根据市场研究机构预测&#xff0c;到2025年全球AI绘画市场规模将达到100亿美元&#xff0c;其中Stable Diffusion&#xff08;简称SD&#xff09;作为一种先进的图像生成技术之一&#xff0c;市场份额也在不断增长&…

惊喜操作!强制DeepSeek和豆包轻松生成你的专属图片提示词

大家好&#xff0c;我是抖知书&#xff01;大伙儿平时用DeepSeek或者豆包&#xff0c;多半是写文章、搞数据&#xff0c;谁会天天想着用它生成图片啊&#xff1f;不过话说回来&#xff0c;还真有人动这个心思。 很多人大概觉得&#xff0c;AI不就是弄文字、数据的么&#xff1…

缓存之美:Guava Cache 相比于 Caffeine 差在哪里?

大家好&#xff0c;我是 方圆。本文将结合 Guava Cache 的源码来分析它的实现原理&#xff0c;并阐述它相比于 Caffeine Cache 在性能上的劣势。为了让大家对 Guava Cache 理解起来更容易&#xff0c;我们还是在开篇介绍它的原理&#xff1a; Guava Cache 通过分段&#xff08;…

日期类、Date、Calendar、IO 流、File

DAY9.2 Java核心基础 日期类 java对日期使用提供了良好的封装&#xff0c;包括java.util.Date和java.util.Calender Date Date类使用比较简单&#xff0c;直接通过构造函数实例化对象接口&#xff0c;Date对象标识当前的系统时间&#xff0c;默认的格式并不是我们所熟悉的&…