【Linux】Linux2.6内核进程调度队列与调度原理

news2024/12/26 15:56:03

在这里插入图片描述

目录

  • 一、进程管理中的部分概念
  • 二、寄存器
  • 三、进程切换
  • 四、Linux2.6内核进程调度队列与调度原理
  • 结尾

一、进程管理中的部分概念

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

上面四个概念中竞争性、独立性和并行都非常好理解,下面对并发进行着重讲解。

在操作系统中,所有的进程都不是占有了CPU就一直运行,而是每隔一段时间,自动就会被CPU剥离下来,这里的一段时间指的是时间片,在后面的文章中会着重讲解,一个时间片通常为几毫秒,假设为1毫秒,如果操作系统中有10个进程要运行,那么在一秒这个期间中,每个进程都能被运行100次,例如这种在一段时间内,让多个进程同时得以推进的情况,我们称之为并发。

Linux内核是基于时间片轮转式抢占式内核,所以Linux内核支持进程之间进行CPU资源的抢占,例如一个优先级为80的进程正在运行,而此时有一个优先级为60的进程要运行,那么CPU会将优先级为80的进程剥离下来,运行优先级为60的进程。


二、寄存器

在CPU中有很多寄存器,例如大家熟知的eax、ebx、ecx、edx、ss、ds、cs、gs、fs、ebp、esp、eip、status_reg、cr0~cr4等寄存器。

我们在学习C语言后知道,临时变量具有临时性,那么在函数内定义的临时变量,函数结束后,临时变量就会被销毁,是如何返回给外部的呢?以下面的代码为例,我们需要将func函数中ret的值返回给外部,实际上是通过了eax寄存器来实现的,函数在返回时,会将变量的内容存放到eax寄存器中,外部的赋值语句,会将eax寄存器中的内容赋值给外部的变量中,那么这里的寄存器就充当了代码的临时空间。

int func()
{
	int ret = 0;
	// ...
	return ret;
}

int main()
{
	int num = func();
	// ...
	return 0;
}

在我们写代码的时候,通常使用的是顺序结构,也就是代码从上往下运行,但是代码中通常会有循环、函数的存在,当程序/进程进入循环或是跳转到函数时,我们的进程/程序,都能知道进程/程序运行到了哪里,其实就是因为CPU中的寄存器也就是eip寄存器/pc指针,也被称之为程序计数器,程序计数器能够记录下当前正在运行中程序的指令的下一条指令的地址,所以在我们运行的进程/程序能够知道代码运行到了哪里。

我们的程序在运行的时候,会使用这些寄存器的,进程会产生各种各样的数据,需要在寄存器中临时保持。
这里讲到的是单进程的情况,那如果是多进程的情况下会怎么样呢?当有多个进程的时候,各个进程都会在CPU中的寄存器形成临时数据,我们称之为进程的硬件上下文,每个进程的临时数据都是不一样的,但是在CPU中寄存器硬件只有一套,而进程的硬件上下文则是有几个进程就有几套,所以这里有一个很重要的结论:寄存器 != 寄存器的内容,这个结论非常的重要!!!

这里讲到了一个CPU只有一套寄存器硬件,但是进程的硬件上下文却不止一个,那么如何处理CPU的寄存器与进程的上下文的关系,将会在下面的进程切换中讲到。


三、进程切换

在Linux中,进程切换(Process Switching)是操作系统核心功能之一,它允许操作系统同时运行多个程序,虽然实际上CPU在任何给定时刻都只能执行一个程序的指令。进程切换是操作系统管理CPU时间的一种机制,它确保了每个程序都能获得一定的执行时间,从而实现了多任务处理(Multitasking)的能力。

进程切换的基本步骤

  1. 保存当前进程状态
    当一个进程的时间片用完或者因为其他原因(如等待I/O操作完成)而需要被挂起时,操作系统会保存该进程的当前状态,包括程序计数器(PC指针,指向下一条要执行的指令的地址)、CPU寄存器的内容(如通用寄存器、状态寄存器、指令寄存器等)、堆栈信息等。在老版本的Linux的内核中,这些状态信息被保存在该进程的进程控制块(PCB)中,而在新版本的Linux内核中,这些状态并不是直接保存到PCB中,但还是与PCB相关,因为直接保存这些信息会导致PCB变大,而现在内核也对PCB的大小做出了限制,所以这些信息不是在PCB中直接保存,这就涉及到了PCB中的tss任务数据段,理解起来比较复杂,会在后面的文章中讲到,目前大家可以认为这些信息是保存在PCB中的。
    在这里插入图片描述

  2. 选择下一个进程
    操作系统会基于某种调度算法(如轮转调度、优先级调度、最短作业优先等)来选择一个进程来执行。调度算法的选择和设计直接影响到系统的性能和公平性。

  3. 恢复新进程的状态
    一旦选定了下一个要执行的进程,操作系统就会从该进程的PCB中恢复其之前保存的状态信息,包括程序计数器、CPU寄存器的内容等。这样,CPU就可以从该进程上次停止的地方继续执行了。

  4. 更新PCB和系统状态
    进程切换后,操作系统会更新相关PCB和系统状态,如修改进程状态、更新调度队列等,以便下次调度时使用。

值得注意的是将进程的上下文保存在PCB后,寄存器中的信息并不是被清除,而是被下一个进程的上下文中的信息直接覆盖,若进程没有上下文是一个新进程,那么会将进程跑起来,慢慢的将寄存器中原来的信息覆盖掉。

四、Linux2.6内核进程调度队列与调度原理

每一个CPU会维护一个自己的运行队列,下图是Linux2.6内核中进程队列的数据结构。

在这里插入图片描述

在图中我们可以看到,运行队列中有数组queue[140],全称为task_struct* queue[140],它是一个指针数组,用来管理进程的优先级,在操作系统中,优先级被分为了两种:

  1. 实时优先级:对应数组的0 ~ 99,共100个优先级。(目前来说不是很重要,不过多做讲解)
  2. 普通优先级:对应数组的100 ~ 139,共40个优先级。(细心一点能够看出,其实这里的普通优先级,就是上一篇文章讲到的进程优先级,使用映射的方法,将优先级60 ~ 99映射到了数组的100 ~ 139中)

在图中还可以发现,运行队列中维护两个queue[140],两个queue[140]分别用来维护活跃进程和过期进程,维护两个queue[140]的原因是因为运行队列中如果只维护一个queue[140]的话,一直启动优先级较高的进程会导致优先级较低的进程无法被CPU被调度,不符合Linux内核的较为公平的调度。

运行队列中还维护了两个指针 void* active 和 void* expired 分别用来指向两个数组queue[140],指针active指向的活跃队列,指针expired指向的是过期队列,CPU调度进程的时候会在活跃队列中优先级高的进程,当进程在一个时间片的时间内运行完后会出现两种情况,一是进程运行完毕,进程退出,二是进程未运行完毕,将该进程交给过期队列进行维护。若正常启动新的进程,是交给过期队列维护而不是活跃队列,以防出现上述不公平的调度,若启动的新进程需要进程抢占,则将新进程交给活跃队列进行维护。活跃队列中的进程会逐渐减少,过期队列中的进程会逐渐增多,当活跃队列中已经没有进程时,将指针active与指针expired指向的内容进行交换,那么活跃队列变为过期队列,过期队列变为活跃队列,重复这样的操作,可以保证Linux内核较为公平的调度每一个进程。

那么如何知道活跃队列中是否有进程呢?CPU应该调度哪个进程?如果每次调度进程都需要遍历一次数组,那么会导致效率低下,我们仔细再看看上图,对应的还有数组int bitmap[5],也就是位图,一个int类型的变量是32位,那么这个数组就160位,一个位能对应一个优先级,那么160位比特位完全能够对应140个优先级。在这个bitmap中,每个bit位代表一个优先级队列,如果该位为1,则表示对应的优先级队列中有进程存在;如果为0,则表示队列为空。通过读取几个或几十个比特位即可判断队列中是否含有进程。运行队列中还维护了一个变量br_active,用来存储队列有有多少个进程。

总结

在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法!这种算法通过优先级队列和位图等数据结构,实现了高效的进程调度。


结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹

在这里插入图片描述

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

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

相关文章

Qt 详解QRubberBand

文章目录 QRubberBand 简介前言 QRubberBand 的作用QRubberBand 的主要功能QRubberBand 的常用方法QRubberBand 的典型应用场景示例代码总结 QRubberBand 简介 前言 在 Qt 中,QRubberBand 是一个非常实用的控件,它通常用于图形界面中的“选择区域”功能…

python股票数据分析(Pandas)练习

需求: 使用pandas读取一个CSV文件,文件内容包括股票名称、价格和交易量。完成以下任务: 找出价格最高的股票; 计算总交易量; 绘制价格折线图。 代码实现: import pandas as pd import matplotlib.pyplot …

Jenkins Nginx Vue项目自动化部署

目录 一、环境准备 1.1 Jenkins搭建 1.2 NVM和Nodejs安装 1.3 Nginx安装 二、Jenkins配置 2.1 相关插件安装 2.2 全局工具安装 2.3 环境变量配置 2.4 邮箱配置(构建后发送邮件) 2.5 任务配置 三、Nginx配置 3.1 配置路由转发 四、部署项目 …

JUnit介绍:单元测试

1、什么是单元测试 单元测试是针对最小的功能单元编写测试代码(Java 程序最小的功能单元是方法)单元测试就是针对单个Java方法的测试。 2、为什么要使用单元测试 确保单个方法运行正常; 如果修改了代码,只需要确保其对应的单元…

乘积求导法则、除法求导法则和链式求导法则

乘积求导法则、除法求导法则和链式求导法则 1. Constant multiples of functions (函数的常数倍)2. Sums and differences of functions (函数和与函数差)3. Products of functions via the product rule (通过乘积法则求积函数的导数)4. Quotients of functions via the quoti…

飞塔防火墙只允许国内IP访问

飞塔防火墙只允许国内IP访问 方法1 新增地址对象,注意里面已经细分为中国内地、中国香港、中国澳门和中国台湾 方法2 手动新增国内IP的对象组,目前好像一共有8632个,每个对象最多支持600个IP段

深度学习 | pytorch + torchvision + python 版本对应及环境安装

Hi,大家好,我是半亩花海。要让一个基于 torch 框架开发的深度学习模型正确运行起来,配置环境是个重要的问题,本文介绍了 pytorch、torchvision、torchaudio 及 python 的对应版本以及环境安装的相关流程。 目录 一、版本对应 二…

JVM:即时编译器,C2 Compiler,堆外内存排查

1,即时编译器 1.1,基本概念 常见的编译型语言如C,通常会把代码直接编译成CPU所能理解的机器码来运行。而Java为了实现“一次编译,处处运行”的特性,把编译的过程分成两部分,首先它会先由javac编译成通用的…

5G学习笔记之随机接入

目录 1. 概述 2. MSG1 2.1 选择SSB 2.2 选择Preamble Index 2.3 选择发送Preamble的时频资源 2.4 确定RA-RNTI 2.5 确定发送功率 3. MSG2 4. MSG3 5. MSG4 6. 其它 6.1 切换中的随机接入 6.2 SI请求的随机接入 6.3 通过PDCCH order重新建立同步 1. 概述 随机接入…

B站狂神说Mybatis+Spring+SpringMVC整合理解(ssm框架整合)

文章目录 0.写在前面(对mybatis,spring的理解)(不看可跳过)0.1 为什么需要mybatis0.2 为什么需要spring0.3为什么需要springmvc 1.新建ssmbuild数据库2.新建Maven项目3.初始化步骤3.1 配置下载maven依赖,构建资源导出3.2 连接数据库3.3建包&a…

JS的魔法三角:constructor、prototype与__proto__

在JavaScript中,constructor、prototype和__proto__是与对象创建和继承机制紧密相关的三个概念。理解它们之间的关系对于掌握JavaScript的面向对象编程至关重要。下面将详细介绍这个魔法三角: 1. constructor 定义:constructor是一个函数&am…

SQL调优分析200倍性能提升

原始SQL: selectdistinct cert.emp_id fromcm_log cl inner join(selectemp.id as emp_id,emp_cert.id as cert_id fromemployee emp left joinemp_certificate emp_cert on emp.id emp_cert.emp_id whereemp.is_deleted0) cert on (cl.ref_tableEmployee and c…

逆向攻防世界CTF系列42-reverse_re3

逆向攻防世界CTF系列42-reverse_re3 参考:CTF-reverse-reverse_re3(全网最详细wp,超4000字有效解析)_ctfreverse题目-CSDN博客 64位无壳 _int64 __fastcall main(__int64 a1, char **a2, char **a3) {int v4; // [rsp4h] [rbp-…

【韩顺平老师Java反射笔记】

反射 文章目录 基本使用反射机制java程序在计算机有三个阶段反射相关的主要类 反射调用优化Class类的常用方法获取Class对象的6种方式哪些类型有Class对象类加载类加载时机类加载过程图 通过反射获取类的结构信息第一组:java.lang.Class类第二组:java.la…

【热门主题】000075 探索嵌入式硬件设计的奥秘

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…

Swift实现高效链表排序:一步步解读

文章目录 前言摘要问题描述题解解题思路Swift 实现代码代码分析示例测试与结果 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗留问题,最近有时间将以往遗留问题一一完善。 148. 排序链表 不积跬步,无以至千里;不积小流…

mysql系列2—InnoDB数据存储方式

背景 本文将深入探讨InnoDB的底层存储机制,包括行格式、页结构、页目录以及表空间等核心概念。通过全面了解这些基础概念,有助于把握MySQL的存储架构,也为后续深入讨论MySQL的索引原理和查询优化策略奠定了基础。 1.行格式 mysql中数据以行…

vue实现echarts饼图自动轮播

echarts官网:Examples - Apache ECharts echartsFn.ts 把echarts函数封装成一个文件 import * as echarts from "echarts";const seriesData [{"value": 12,"name": "过流报警"},{"value": 102,"name&qu…

【Python数据分析五十个小案例】使用自然语言处理(NLP)技术分析 Twitter 情感

博客主页:小馒头学python 本文专栏: Python爬虫五十个小案例 专栏简介:分享五十个Python爬虫小案例 项目简介 什么是情感分析 情感分析(Sentiment Analysis)是文本分析的一部分,旨在识别文本中传递的情感信息&…

网络安全防护指南:筑牢网络安全防线(5/10)

一、网络安全的基本概念 (一)网络的定义 网络是指由计算机或者其他信息终端及相关设备组成的按照一定的规则和程序对信息收集、存储、传输、交换、处理的系统。在当今数字化时代,网络已经成为人们生活和工作中不可或缺的一部分。它连接了世…