Linux笔记---进程:进程切换与O(1)调度算法

news2024/11/25 9:57:39

1. 补充概念

1.1 并行与并发

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

由于在一个操作系统中进程的数量通常是很多的,所以并发的调度方式必不可少,在这篇文章中,我们要详细探讨进程是如何切换的。

1.2 实时操作系统与分时操作系统

  • 实时操作系统:是指系统能够及时响应外部事件的请求,在规定的时间范围完成对该事件的处理,并控制实时任务协调一致地运行。实时操作系统分为硬实时系统(如火箭和导弹控制)和软实时系统(如银行),需要具备实时时钟管理、过载防护和高可靠性等能力。
  • 分时操作系统:是一种允许多个用户同时共享一台计算机资源的操作系统。它通过将计算机的处理能力划分为多个时间片,轮流分配给不同的用户进程,使得每个用户都能在短时间内得到系统的响应,就好像独占使用整个系统一样。
  • 时间片:当代计算机都是分时操作系统,每个进程都有它合适的时间片(其实就是一个计数器)。时间片到达,进程就被操作系统从CPU中剥离下来,接着其他进程将占据CPU资源,该进程回到运行队列重新排队。

 进程的时间片用完就被CPU换下,让其他进程抢占CPU资源,这一点很好理解,但有两个问题:

  1. 当一个程序再次获得CPU资源时,如何接着上次运行的进度来继续运行?
  2. CPU是如何由优先级来决定谁该抢占CPU资源的?或者说优先级是如何实现的?

2. CPU上下文切换

在Linux操作系统中,CPU上下文切换是指在多任务处理时,CPU从一个任务切换到另一个任务的过程。这个过程包括保存当前任务的CPU寄存器和程序计数器的值,加载新任务的上下文到这些寄存器和程序计数器,然后跳转到程序计数器所指的新位置,开始运行新任务。

上下文切换的目的是为了让多个任务看起来像是同时运行,而实际上CPU在短时间内轮流执行这些任务。 

简单来说,每个进程在被换下时,会将当前CPU中寄存器的内容(上下文数据)保存到自己的PCB中维护起来,再将即将执行的进程的上下文数据加载到CPU中。

在task_struct中存在字段struct tss_struct tss,该结构体就用来保存进程的上下文数据。

struct tss_struct {
    struct x86_hw_tss x86_tss;
    unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
    unsigned long stack[64];
} ____cacheline_aligned;

struct x86_hw_tss {
    unsigned short back_link, __blh;
    unsigned long sp0;
    unsigned short ss0, __ss0h;
    unsigned long sp1;
    unsigned short ss1, __ss1h;
    unsigned long sp2;
    unsigned short ss2, __ss2h;
    unsigned long __cr3;
    unsigned long ip;
    unsigned long flags;
    unsigned long ax;
    unsigned long cx;
    unsigned long dx;
    unsigned long bx;
    unsigned long sp;
    unsigned long bp;
    unsigned long si;
    unsigned long di;
    unsigned short es, __esh;
    unsigned short cs, __csh;
    unsigned short ss, __ssh;
    unsigned short ds, __dsh;
    unsigned short fs, __fsh;
    unsigned short gs, __gsh;
    unsigned short ldt, __ldth;
    unsigned short trace;
    unsigned short io_bitmap_base;
} __attribute__((packed));
  1. x86_tss: 这是一个x86_hw_tss类型的结构体,它定义了硬件状态信息,包括寄存器的值、堆栈指针等。
  2. io_bitmap: 这是一个unsigned long类型的数组,用于存储I/O权限位图。
  3. stack: 这是一个unsigned long类型的数组,用于存储紧急内核堆栈。

上下文切换的性能影响

上下文切换是有一定开销的,每次上下文切换都需要几十纳秒到数微秒的CPU时间。特别是在进程上下文切换次数较多的情况下,很容易导致CPU将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间

3. O(1)调度算法

接下来的问题就是,操作系统如何根据优先级决定下一个接手CPU资源的进程是哪一个。

加入依次检查调度队列中的进程的优先级并从中选择的话,时间复杂度会达到O(n)。

O(1)调度算法是Linux内核中的一种进程调度算法,其名称中的“O(1)”表示该算法的时间复杂度是常数级别的,与系统中的进程数量无关。这种算法的设计目的是为了解决O(n)调度算法在处理大量进程时效率低下的问题。

下图是Linux中运行队列的结构示意图:

 我们要讨论的核心在于:

3.1 prio_array结构体

在runqueue中有一个只含两个元素的结构体数组字段,即图中的array[0]和array[1]:

struct prio_array {
    unsigned int nr_active; /* 本组中待处理进程的总数 */
    unsigned long bitmap[BITMAP_SIZE]; /* 用位图的方式表示某个优先级上有没有待处理的进程队列 */
    struct list_head queue[MAX_PRIO]; /* 与bitmap对应,存储所有待运行的进程 */
};

// #define 5 BITMAP_SIZE
// #define 140 MAX_PRIO
  1. nr_active:表示本组中待处理进程的总数。
  2. bitmap:这是一个位图,用于表示某个优先级上是否有待处理的进程队列。位图中的每一位对应一个优先级,1表示该优先级上有待处理的进程队列,0表示没有。
  3. queue:这是一个队列数组,用于存储所有待运行的进程。数组的下标对应进程的优先级,每个元素都是一个队列,队列中的节点是具有相同优先级的进程。例如,优先级为124的进程会被放到下标为124的队列中排队。

 根据上面的信息可以知道,整个操作系统中的优先级范围为[0,140),共140种:

  • 普通优先级:100〜139(对应nice值可取的40种优先级)。
  • 实时优先级:0〜99(不关心)。

通过让不同优先级的进程到不同的队列中排队,并按下标从低到高地调度每个队列,就保证了优先级高的进程先被执行。

bitmap是一个位图,包含5个整形元素,共160个比特位,前140个比特位依次对应140个优先级的队列 。通过这个bitmap就可以快速定位到非空的队列,而不用依次查找每个队列。

效率以及优先级如何保证的问题解决了,但是,被调度过后需要重新排队的进程以及新加入的进程应该被添加到哪里呢?假设重新添加到当前的queue中,那么在优先级高的进程被完全执行完毕之前,优先级较低的进程都不会被执行。

为了解决这个问题,我们提出了活跃队列和过期队列的概念。

3.2 活跃队列与过期队列

O(1)调度算法通过维护两个运行队列来实现:活动队列(active queue)和过期队列(expired queue)。活动队列中的进程是有资格获取CPU时间片的进程,而过期队列中的进程是已经用完时间片的进程。操作系统始终只会调度活动队列中的进程。

活动队列中的进程的时间片被用完之后会被添加到过期队列中,重新排队的同时,防止其一直占用CPU资源。

array[0]和array[1]轮流成为活动队列和过期队列,当活动队列中所有的进程都用完时间片,也就是活动队列中没有可运行的进程时,活动队列和过期队列进行交换。此时原来的过期队列变为活动队列,而原来的活动队列变为过期队列,新的活动队列中的进程又可以开始竞争CPU资源。

谁是活动队列,谁是过期队列,取决于active指针和expired指针的指向。

3.3 O(1)调度算法的优点

  • 高效性:由于查找下一个要运行的进程的时间复杂度为O(1),无论系统中有多少个进程都能快速地做出调度决策,提高了系统的响应速度和整体性能。
  • 公平性:保证了分时操作系统调度进程的公平性,每个进程都有机会运行。

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

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

相关文章

使用ENSP实现浮动静态路由

一、项目拓扑 二、项目实现 1.路由器AR1配置 进入系统试图 sys将路由器命名为R1 sysname R1关闭信息中心 undo info-center enable 进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为1.1.1.1/24 ip address 1.1.1.1 24进入g0/0/1接口 int g0/0/1将g0/0/1接口IP地址配置为2.…

GoF设计模式——结构型设计模式分析与应用

文章目录 UML图的结构主要表现为:继承(抽象)、关联 、组合或聚合 的三种关系。1. 继承(抽象,泛化关系)2. 关联3. 组合/聚合各种可能的配合:1. 关联后抽象2. 关联的集合3. 组合接口4. 递归聚合接…

【论文复现】深度知识追踪

📝个人主页🌹:Eternity._ 🌹🌹期待您的关注 🌹🌹 ❀ 深度知识追踪 1. 论文概述2. 论文方法3. 实验部分3.1 数据集3.2 实验步骤3.3 实验结果 4 关键代码 1. 论文概述 知识追踪的任务是对学生的知…

Linux: 进程地址空间(理解虚拟地址和页表)

目录 1. 虚拟地址 2. 进程地址空间分布 3. 描述进程地址空间 4. 内存管理——页表 5. 父子进程的虚拟地址关系 6. 页表标记位 6.1 读写权限 6.2 命中权限 7.为什么存在进程地址空间 1. 虚拟地址 #include <stdio.h> #include <unistd.h> #include <sy…

C语言:深入理解指针

一.内存和地址 我们知道计算机上CPU&#xff08;中央处理器&#xff09;在处理数据的时候&#xff0c;需要的数据是在内存中读取的&#xff0c;处理后的数据也会放回内存中&#xff0c;那我们买电脑的时候&#xff0c;电脑上内存是 8GB/16GB/32GB 等&#xff0c;那这些内存空间…

transformer.js(一):这个前端大模型运行框架的可运行环境、使用方式、代码示例以及适合与不适合的场景

随着大模型的广泛应用&#xff0c;越来越多的开发者希望在前端直接运行机器学习模型&#xff0c;从而减少对后端的依赖&#xff0c;并提升用户体验。Transformer.js 是一个专为前端环境设计的框架&#xff0c;它支持运行基于 Transformer 架构的深度学习模型&#xff0c;尤其是…

uni-app 发布媒介功能(自由选择媒介类型的内容) 设计

1.首先明确需求 我想做一个可以选择媒介的内容&#xff0c;来进行发布媒介的功能 &#xff08;媒介包含&#xff1a;图片、文本、视频&#xff09; 2.原型设计 发布-编辑界面 通过点击下方的加号&#xff0c;可以自由选择添加的媒介类型 但是因为预览中无法看到视频的效果&…

行业分析---2024年小鹏汽车AI Day及三季度财报

1 背景 在之前的博客中&#xff0c;笔者撰写了多篇行业类分析的文章&#xff08;科技新能源&#xff09;&#xff1a; 《行业分析---我眼中的Apple Inc.》 《行业分析---马斯克的Tesla》 《行业分析---造车新势力之蔚来汽车》 《行业分析---造车新势力之小鹏汽车》 《行业分析-…

数据可视化复习1-Matplotlib简介属性和创建子图

1.Matplotlib简介 Matplotlib是一个Python的2D绘图库&#xff0c;它可以在各种平台上以各种硬拷贝格式和交互环境生成具有出版品质的图形。通过Matplotlib&#xff0c;开发者可以仅需要几行代码&#xff0c;便可以生成绘图、直方图、功率谱、条形图、错误图、散点图等。 以下…

WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理

WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理 1. 标题识别elementUI组件爆红 这个原因是&#xff1a; 在官网说明里&#xff0c;才版本2024.1开始&#xff0c;默认启用的 Vue Language Server&#xff0c;但是在 Vue 2 项目…

如何安全删除 Linux 用户帐户和主目录 ?

Linux 以其健壮性和灵活性而闻名&#xff0c;是全球服务器和桌面的首选。管理用户帐户是系统管理的一个基本方面&#xff0c;包括创建、修改和删除用户帐户及其相关数据。本指南全面概述了如何在 Linux 中安全地删除用户帐户及其主目录&#xff0c;以确保系统的安全性和完整性。…

如何利用ros搭建虚拟场景通过仿真机器人完成一次简单的SLAM建图、导航规划(超简单)?——学习来源:机器人工匠阿杰

一&#xff1a;什么是SLAM&#xff0c;SLAM和导航规划又有什么关系&#xff1f; SLAM&#xff08;Simultaneous Localization and Mapping&#xff0c;即同时定位与建图&#xff09;是一种在未知或动态环境中自行驶的重要技术。主要通过设备上的传感器&#xff08;如激光雷达、…

shell脚本(完结)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;shell编程&#xff08;完结&#xff09;_哔哩哔哩_bilibili 本文主要讲解不同shell脚本中的相互调用以及输入输出重定向操作。 一、不同脚本之间…

禁用达梦DEM的agent

agent占用内存较多&#xff0c;实际没什么使用&#xff0c;考虑停止agent 应该切换到root执行停止 cd /dm/dmdbms/tool/dmagent/service/ ./DmAgentService stop禁用

使用ChatGPT生成和优化电子商务用户需求规格说明书

在电子商务项目开发中&#xff0c;用户需求规格说明书&#xff08;User Requirement Specification, URS&#xff09;是团队沟通与项目成功的基石。然而&#xff0c;面对复杂多变的需求&#xff0c;如何快速生成清晰、完整且具备说服力的文档&#xff1f;这正是AI工具的用武之地…

产品研发管理和研发项目管理的区别是什么

产品研发管理与研发项目管理有显著的区别&#xff0c;主要体现在管理范围、目标导向和执行方法上。产品研发管理侧重于产品生命周期的规划与执行&#xff0c;强调产品的创新性和市场需求对接&#xff0c;而研发项目管理则更注重具体项目的执行过程&#xff0c;聚焦项目时间、成…

摆烂仙君传——深度学习秘境奇缘

第一章&#xff1a;深度学习秘境 在修仙界与科技交织的边缘&#xff0c;八荒六合九天无上摆烂仙君在其高科技修炼室中感应到一股神秘的召唤。这股力量似乎与他的灵魂产生了共鸣&#xff0c;引导他前往传说中的深度学习秘境。在那里&#xff0c;古老的仙法与前沿的算法交织&…

【FPGA开发】Vivado自定义封装IP核,绑定总线

支持单个文件的封装、整个工程的封装&#xff0c;这里用单个文件举例。 在文件工程目录下&#xff0c;自建一个文件夹&#xff0c;里面放上需要封装的verilog文件。 选择第三个&#xff0c;指定路径封装&#xff0c;找到文件所在目录 取个名&#xff0c;选择封装IP的路径 会…

【CS61A 2024秋】Python入门课,全过程记录P2(Week3开始,更新中2024/11/24)

文章目录 关于基本介绍&#x1f44b;Week 3Mon Environments阅读材料Lab 02: Higher-Order Functions, Lambda ExpressionsQ1: WWPD: The Truth Will PrevailQ2: WWPD: Higher-Order FunctionsQ3: WWPD: Lambda 关于 个人博客&#xff0c;里面偶尔更新&#xff0c;最近比较忙。…

在Linux下配置gitee与Github的远程仓库

目录 前言 云服务器下载git 检测是否下载成功git Linux下配置gitee远程仓库 代码提交演示 git三板斧 Linux下配置Github远程仓库 最后的提醒 前言 那么本篇文章将是在&#xff0c;你已经创建了本地仓库的基础上&#xff0c;在Linux下配置gitee的远程仓库的步骤&#xff…