Linux相关概念和重要知识点(11)(进程调度、Linux内核链表)

1.Linux调度算法

上篇文章我粗略讲过queue[140]的结构,根据哈希表,我们可以将40个不同优先级的进程借助哈希桶链入queue[140]中。调度器会根据queue的下标来进行调度。但这个具体的调度过程是怎样的呢?以及runqueue和queue[140]的关系是什么?我们需要更深入了解

(1)queue

PCB* queue[140]只是一个成员变量,它存在于另一个结构体queue中。

我们可以用数组queue[140]和结构体queue来区分它们。

当有PCB从里面链入或者链出时,nr_active和bitmap都会相应更新

我们可以知道,一个结构体queue就能将进程按优先级处理完,但进程的处理是动态的过程,我们要知道他是怎么流转起来的。这就需要知道runqueue的结构了。

(2)runqueue

runqueue是以结构体queue为基本结构,为满足动态调度而建立起来的。其中active活跃指针指向的array里面的PCB* queue[140]就是CPU正在调度的PCB队列,换句话说,调度器只会从active指向的PCB队列中调度进程。这样实现为什么呢?那另一个array干什么呢?我们需要设想,如果在CPU执行的过程中由新的进程加入进来怎么办?同时,CPU要如何在既保证优先级又保证较为公平的调度呢?

(3)调度算法

①新增:当有新的进程加入runqueue时,它并不会直接加入active指向的队列,而是会链入expired指向的结构体queue里面的PCB* queue[140],链入规则和前面一样,都遵循哈希算法。

②现有的进程:当active指向的队列里的一个进程被执行完一次之后,它并不会被链入到当前active对应的PCB* queue[140],而是会和那些新进程一样,链入expired指向的PCB* queue [140]中。

③完成的进程:当有进程在active被执行一次并完成后,就会进入Z+X状态,就不会被链入expired里面的PCB* queue [140],等着被父进程读取回收就行了

我们发现,expired对应的PCB* queue [140]对应的PCB*越来越多(nr_active也增大),而active对应的PCB* queue [140]却越来越少(nr_active减小)。当nr_active == 0时,active和expired的指针交换,这个时候我们就发现expired(原来的active)空了,active(原来的expired)满了。接下来就继续按上述规则执行(active取,放回expired,新增放入expired),如此往复,一个动态的调度过程就形成了。

从上述过程我们就能发现整个调度过程既保证了优先级,也保证了公平性,同时新增入的进程也不会和正在执行的进程发生冲突。调用规则保证了每一次循环active里面的每一个PCB都会被执行(nr_active记录PCB*数量,每调用一次就减1,不会遗漏),而按照顺序调用又保证了优先级,即优先级高的先执行,低的后执行。

(4)bitmap存在的意义

runqueue中active、expired、array[2]存在的意义很明确,没有它们就构不成整个调度的流转,上述的过程就是它们存在的意义。对于queue来说,nr_active用于记录PCB*的数量,即active、expired分别指向的结构体里进程的数量,只有当active里面的进程调度完了(nr_active == 0)才会swap两个指针,它明确了每次swap的时机,也保证了调度进程的公平性。

但还有个细节,那就是遍历PCB* queue [140]效率不高,明明数组可以随机访问,但又要保证所有PCB都被访问,所以就有bitmap的出现。通过160位bit我们可以得到140个位置存放PCB的情况,比如假定bitmap[0]是5,根据101B,我们得到PCB* queue[140]的第0位和第2位有进程,其余30位都没有进程,可以直接跳过。每个int我们就可以扫掉32个位置,效率很高。具体操作涉及到位操作,之前也有讲过一些位操作得到1或0的办法,很多,这里我们明白是怎么一回事即可。

总结:这是一个进程饥饿问题(公平与优先级的矛盾),采用双queue来解决问题,使得active永远处于存量竞争状态,随着时间竞争越来越小,再交换指针重复操作,实现公平与优先级共存。整个调度算法框架的时间复杂度控制在O(1),效率很高。

2.Linux内核链表

我们常见的链表无外乎分为带头和不带头、单向还是双向、循环还是不循环。这种链表有个共同特点,就是数据和链绑定在了一起。但在Linux内核中,一个PCB,它有可能既是在queue队列,又有可能在waitqueue,那么我们应该怎么做呢?这就是Linux的内核链表,它将链和数据分离,用位操作来访问,极大增强了数据链接和访问的效率。

但这种链表访问数据很麻烦,因为我们只能得到链表连接点的地址,而其它地方的地址并不好拿,我们要想办法拿到struct的起始地址。思路是&(struct  A*)0->(要查找的成员变量链接点)可以得到偏移量offset(宏),再使用(链接点) - offset得到struct A的起始地址,之后就能正常访问了。难点在C语言,学习过偏移量和宏应该能很快理解。

PCB之间就是用这种链表联系起来的,在不同状态切换的效率上很有优势

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

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

相关文章

[C++] 剖析AVL树功能的实现原理

文章目录 引言AVL树的关键性质为什么选择AVL树? AVL树的结构节点对象的类 AVL树的插入检查是否为空树并处理根节点查询插入位置(非递归)插入节点并连接父节点更新平衡因子(在失去平衡的条件下进行旋转) 旋转旋转的原则…

基于ssm的学生社团管理系统 社团分配系统 社团活动调度平台 学生社团管理 信息化社团管理开发项目 社团活动管理 社团预约系统(源码+文档+定制)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

VMware中Ubuntu系统Docker正常运行但网络不通(已解决)

问题描述:在VMware中的Ubuntu系统下部署了Docker,当在docker容器中运行Eureka微服务时,发现Eureka启动正常,但无法通过网页访问该容器中Eureka。 解决办法如下: 1、创建桥接网络:test-net sudo docker n…

一文带你入门客制化键盘,打造专属打字利器

我用过不少键盘,但是都不太符合自己的需求,最后还是走向了客制化。 客制化,可以理解为自定义、DIY,自己动手拼装出一把只属于自己的键盘。 本文会对客制化做个简单的介绍,旨在读者能自己简单拼装出一款键盘。 目前市…

QStyle文档

前言 本文翻译自Qt官方文档,详细介绍了各成员/类型的作用,包含部分示例代码。 QStyle类的内容非常庞大,如需快速了解类成员和使用简介,请参见 QStyle简介。 一、QStyle Class QStyle是一个抽象基类,封装了GUI的外观…

OpenGL笔记之事件驱动设计将相机控制类和应用程序类分离

OpenGL笔记之事件驱动设计将相机控制类和应用程序类分离 —— 2024-10-02 下午 code review! 文章目录 OpenGL笔记之事件驱动设计将相机控制类和应用程序类分离1.代码图片2.分析3.UML4.代码 1.代码图片 运行 Mouse button 1 pressed at (100, 200) Mouse dragged by (50, 50)…

Spring(学习笔记)

<context:annotation-config/>是 Spring 配置文件中的一个标签&#xff0c;用于开启注解配置功能。这个标签可以让 Spring 容器识别并处理使用注解定义的 bean。例如&#xff0c;可以使用 Autowired 注解自动装配 bean&#xff0c;或者使用 Component 注解将类标记为 bea…

10/02赛后总结

T1学习除法 题目传送门&#xff1a;学习除法http://bbcoj.cn/contest/1028/problem/1 说白了&#xff0c;就是检验是不是质数罢了&#xff0c;是质数输出0&#xff0c;不然输出1&#xff1b; 但是质数判断写错了 100分只有60分&#xff0c;damn #include<bits/stdc.h>…

【Linux】进程间关系与守护进程

超出能力之外的事&#xff0c; 如果永远不去做&#xff0c; 那你就永远无法进步。 --- 乌龟大师 《功夫熊猫》--- 进程间关系与守护进程 1 进程组2 会话3 控制终端4 作业控制5 守护进程 1 进程组 之前我们提到了进程的概念&#xff0c; 其实每一个进程除了有一个进程 ID(P…

Django5 使用pyinstaller打包成 exe服务

首先&#xff1a;确保当前的django项目可以完美运行&#xff0c;再进行后续操作 python manage.py runserver第一步 安装 pyinstaller pip install pyinstaller第二步 创建spec 文件 pyinstaller --name manage --onefile manage.pypyinstaller&#xff1a;这是调用 PyInsta…

数据异质性与数据异构性的本质和举例说明

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 在现代数据科学与信息技术领域&#xff0c;“数据异质性” 与 “数据异构性” 是两个常见的概念。对于初学者而言&#xff0c;明确这两个概念的本质及其间的差异至关重要。本文旨在以简明易懂的方式&am…

Python笔记 - 利用装饰器设计注解体系

认识注解 注解&#xff08;Annotation&#xff09;是一种用于为代码添加元数据的机制。这些元数据可以在运行时被访问&#xff0c;用于为代码元素&#xff08;如类、方法、字段等&#xff09;提供额外的信息或指示。 由于Python中装饰器只能装饰类和方法&#xff0c;因此也只…

Mac 网络连接正常,微信可以使用,但浏览器打不开网页?

解决&#xff1a; Step1&#xff0c;选择&#x1f34e;图标&#xff0c;选择系统设置&#xff08;或系统偏好设置&#xff09;打开&#xff1b; Step2&#xff0c;选择网络&#xff0c;Wi-Fi Step3&#xff0c;选择详细信息&#xff1b; Step4: 选择代理&#xff0c;关闭右…

3.点位管理改造-列表查询——帝可得管理系统

目录 前言一、与页面原型差距1.现在&#xff1a;2.目标&#xff1a;3. 存在问题&#xff1a;所在区域和合作商ID展示的都是ID&#xff0c;而不是名称&#xff1b;同时合作商ID应改为合作商 二、修改1.重新设计SQL语句2.修改mapper层&#xff0c;使用Mybatis中的嵌套查询3.修改s…

C. Tree Pruning【Codeforces Round 975 (Div. 1)】

C. Tree Pruning (永远不知道为什么TLE直到把初始化的memset换成for循环 题意很简单&#xff0c;就是找到一个深度&#xff0c;使得删除最少的节点且所有的叶子节点都为这个深度。 从小到大遍历可能的深度i&#xff0c;容易知道所有 深度大于i的节点 和所有 子树最大深度小于i…

操作符详解与表达式求值

目录 操作符分类 1.算数操作符 2.移位操作符&#xff08;只适用于整数范围&#xff09; &#xff08;1&#xff09;引入 &#xff08;2&#xff09;左移操作符<< &#xff08;2&#xff09;右移操作符>> 3.位操作符 4.赋值操作符 复合赋值符 5.单目操作符 5…

深度优先搜索(DFS)与有向图中的唯一结点

深度优先搜索(DFS)与有向图中的唯一结点 前提与定义分析与方法伪代码与 C 代码实现解释结果在图论中,深度优先搜索(DFS)是一种用于遍历或搜索图的算法。DFS 从给定的起始结点出发,沿着图的深度方向尽可能深地搜索,直到无法继续为止,然后回溯并从未访问过的邻接结点继续…

Unraid的cache使用btrfs或zfs?

Unraid的cache使用btrfs或zfs&#xff1f; 背景&#xff1a;由于在unraid中添加了多个docker和虚拟机&#xff0c;因此会一直访问硬盘。然而&#xff0c;单个硬盘实在难以让人放心。在阵列盘中&#xff0c;可以通过添加校验盘进行数据保护&#xff0c;在cache中无法使用xfs格式…

YOLOv11改进 | Neck篇 | YOLOv11引入Slim-Neck(轻量)

1. Slim-Neck介绍 摘要&#xff1a;目标检测是计算机视觉中重要的下游任务。 对于车载边缘计算平台来说&#xff0c;巨大的模型很难达到实时检测的要求。 而且&#xff0c;由大量深度可分离卷积层构建的轻量级模型无法达到足够的精度。 我们引入了一种新的轻量级卷积技术 GSCon…

【顺序查找】

目录 一. 顺序查找的概念二. 查找的性能计算 \quad 一. 顺序查找的概念 \quad \quad 二. 查找的性能计算 \quad