当前位置: 首页 > news >正文

【Linux】进程优先级 | 进程调度(三)

目录

前言:

一、进程优先级:

1.通过nice值修改优先级: 

二、进程切换:

三、上下文数据

四、Linux真实调度算法:

五、bitmap位图:

六、命令总结:

总结:


前言:

我们已经知道了进程的一些属性,和进程的各种状态及孤儿进程,那么接下来我们就需要知道进程的调度方法和优先级,少年,开始吧!

一、进程优先级:

进程优先级也就是获取某种资源的先后顺序。为什么存在?本质就是目标资源较少。

在task_struct中的优先级属性是使用几个int类型的变量表示的。优先级数字越小,优先级越高,也就和我们的排名一样。

为了方便观察,我们依旧写一个死循环的程序:

当我们想查看一个进程的优先级信息,我们可以使用ps -l查看优先级信息:

如果你是新开的Xshell窗口,需要加上-a选项来查看全局的进程。

1.通过nice值修改优先级: 

我们一般是通过修改nice值对优先级进行修改的:

插一嘴:UID是什么?

我们平时文件的拥有者,所属组都是一个字符串,系统做对比的时候所需时间就很多,所以OS会对每一个用户维护一个叫做UID的东西。也就是用户ID(USER identify)。我们可以使用ls -ln来查看。-n选项是把能显示成数字的就显示成数字,尤其是用户。

所以操作系统使用UID来区分进程是谁启动的,所有操作都是进程操作,进程会记录谁启动的我;而文件会记录下拥有者,所属组和对应权限。所以进程去启动相关文件时,就会进行UID的对比,从而实现权限控制。

进程的优先级是为了竞争CPU资源做准备的。 接下来我们修改进程优先级,可以通过指令也可以通过代码修改。

注意这里把nice拉到最大100(原来1767进程PRI为80,NI为0):

之后我们再次把nice值拉到最低-100,并再次观察结果:

可以看到并没有从上次的99加上nice值(-20)得到79,而是从最开始的80加上(-20)得到60最终优先级。 

为什么nice在可控范围以内呢?因为我们使用的是分时OS,在进程调度的时候要尽量公平。

优先级的存在是为了更合理竞争相关资源。

二、进程切换:

当一个进程的时间片到了,进程就要被切换;Linux是基于时间片,进行调度轮转的。但是一个进程的时间片到了并不一定就跑完了,可在任何地方被重新调度切换。

三、上下文数据

当一个进程的时间片到了,OS要保留上下文数据;当其又被调度的时候,OS要恢复上下文数据。

进程在运行的时候,会有很多临时数据,这些数据都在寄存器中保存。CPU内部的寄存器数据,是进程执行时的瞬时状态信息。

我们需要来具体了解几个寄存器,如果各位不知道寄存器是什么,可以先临时了解,就是存放各种信息的东西可以是地址,也可以是数据,寄存器在CPU上。

其中指令指针寄存器(也称IP、PC程序计数器),它里面记录下次要执行的命令的地址;IR(Instruction Register)即指令寄存器,存放的是当前执行代码的地址。 

进程在运行的时候,会有很多临时数据,这些数据都在寄存器中保存。CPU内部的寄存器数据,是进程执行时的瞬时状态信息,只写信息我们可以当做进程的上下文数据。

学过硬件的都知道,每个进程不是都需要用到寄存器吗?IP寄存器即使这次存储了进程A的下次执行地址,但是A的时间片到了,进程B执行,IP内的内容应该是B下次执行的地址;B的时间片到了,CPU调度进程A,有是怎么找进程A的执行地址呢?

我们之前已经讲过PCB(task_struct)里面有一个属性专门保存进程的上下文数据,所以在进程A执行完以后,寄存器中的内容会存放在PCB的上下文数据中,对于B也是,所以下次再次调度A就可以根据PBC来恢复上下文,继续顺序执行代码。

我们找到第一版本的Linux内核代码,其中tast_struct中的一个结构体属性是tss(任务状态段),之后看里面的属性:

可以看到PCB中包含tss_struct(可以理解为保存上下文数据的属性) 

这里面可以看到很多熟悉的寄存器。 所以上下文保存在PCB中,也就是内存中,而不是寄存器中。

我们之前讲到过,进程是通过runqueue的task_struct*head找到第一个进程并让CPU调度,当时间片结束就放在队尾,也就是FIFO(先进先出)的方式。但是我们又讲到了优先级,所以实际上,进程调度并不是FIFO,而是尽量的公平调度。

四、Linux真实调度算法:

所以我们来讲解Linux的真实调度算法:

runqueue队列中,有两个指针维护调度的进程列表。*active活跃的进程列表,*expired过期的进程列表。

进程列表是一个指针数组,前100个是实时进程,我们无法对其改变优先级;后40个是分时进程,我们可以改变优先级。这也就解释了之前的nice值为什么只有40个。

进程真正的优先级范围为[60,99],而优先级为60对应的数组下标为100。

比如此时有一个优先级为61的进程要放入queue中,会61 - 60(startpri) + 100 = 101

如果再来一个进程优先级为61进程,则会连接在第一个进程后面:

这也就是一个哈希桶,但是其实runqueue中包含两个哈希桶,维护两个,接下来我们来具体了解。

为什么要这样设计?比如此时active哈希桶中有一个进程: 

调度一般分为三种情况:

1.运行退出
2.不退出但时间片到了
3.有新进程产生了

第一种情况进程退出程序就释放掉了,我们不做讨论。

我们首先讨论有新进程产生。此时有一个问题,如果一直有新的进程产生,并且创建的新进程优先级一直都是最高的,是不是会和之前讲的调度器要非常均衡的进行进程调度所矛盾?优先级很高,表示一定要一直优先吗?优先级很低,表示要一直等待吗?

这样的话优先级低的进程就永远不会被调度,这叫做进程饥饿问题。

所以新进程会放入expired(过期)哈希桶中,而且时间片到了的进程,也会被放入expired哈希桶中。

所以active哈希桶中,进程只会越来越少,不会增多。 因为时间片会到,进程会退出。

当active为空时,OS会将active和expired指针指向的内容交换(swap(&active, &expired)),之后使用相同的调度算法,轮转执行。

注意:实时进程(0-99)不收调度影响

回到之前queue定义中的nr_active是代表对应当前哈希桶中有多少进程, 它决定要不要交换,当nr_active为0就需要交换。

五、bitmap位图:

而其中的bitmap[5],注意这是一个整形。5个整形也就有5*32=160个bit位,刚好覆盖140。因为实际上还是从上到下进行遍历看桶是否为空,这样还是很慢的。而bitmap就可以快速定位,一次查找32个bit位看是否为空。这是位图的概念。

类似这样:

for(int i = 0; i < 5; ++i) 
{if (bitmap[i] == 0) {continue;}else {//确定在32个比特位那个位置有进程}
}

这就是Linux的进程O(1)算法, 所有的进程都要有链表连接,而且进程可以在调度队列中,阻塞队列中。

Linux中的链式结构为双链表结构。但是它并不是我们想象的那样将数据和指针都放在一个节点中;其实内核中只有链接字段,没有属性字段。

所以一个进程既可以在全局链表中,也可以在任何一个其他数据结构中,只要加上节点字段即可。 

我们进程其实只知道task_struct中的link字段地址,那么它是如何找到结构体的起始地址呢?这其实就是结构体部分的内容。

struct S
{char c1;int a;char c2;
};#define OFFSETOF(struct_name,member_name) (int)&(((struct_name*)0)->member_name)int main()
{struct S s = { 'a', 10, 'b' };//printf("%d\n", OFFSETOF(struct S, c1));//printf("%d\n", OFFSETOF(struct S, a));//printf("%d\n", OFFSETOF(struct S, c2));printf("%p\n", &s);printf("%p\n", (struct S*)( (char*) & s.a - OFFSETOF(struct S, a)));//这是作者自己实现的OFFSETOF宏,各位可以直接使用offsetof宏来求偏移量//使用offsetof要引用stddef.h同文件printf("%p\n", (struct S*)((char*)&s.a - offsetof(struct S, a)));return 0;
}

这里为什么要转换为char*?这样可以按照字节为单位去操作,更好的计算。各位可以试试其他类型,会发现结果并不符合预期。

六、命令总结:

ps -l:查看当前系统中进程状态,将能显示为数字的都显示为数字。

总结:

大佬不愧为大佬,这个调度算法和位图的设计简直无敌,接下来我们就会讲解命令行参数和环境变量,这部分知识也更为炸裂,各位敬请期待!

相关文章:

【Linux】进程优先级 | 进程调度(三)

目录 前言&#xff1a; 一、进程优先级&#xff1a; 1.通过nice值修改优先级&#xff1a; 二、进程切换&#xff1a; 三、上下文数据 四、Linux真实调度算法&#xff1a; 五、bitmap位图&#xff1a; 六、命令总结&#xff1a; 总结&#xff1a; 前言&#xff1a; 我…...

wordpress按不同页调用不同的标题3种形式

在WordPress中&#xff0c;可以通过多种方式根据不同的页面调用不同的标题。这通常用于实现SEO优化、自定义页面标题或根据页面类型显示不同的标题内容。 使用wp_title函数 wp_title函数用于在HTML的title标签中输出页面标题。你可以通过修改主题的header.php文件来实现自定义…...

音频进阶学习十六——LTI系统的差分方程与频域分析一(频率响应)

文章目录 前言一、差分方程的有理式1.差分方程的有理分式2.因果系统和ROC3.稳定性与ROC 二、频率响应1.定义2.幅频响应3.相频响应4.群延迟 总结 前言 本篇文章会先复习Z变换的有理分式&#xff0c;这是之前文章中提过的内容&#xff0c;这里会将差分方程和有理分式进行结合来看…...

css实现左右切换平滑效果

2025.02.25今天我学习了如何用css实现平滑效果 一、html相关代码 &#xff08;1&#xff09;设置往左、往右的动画属性&#xff0c;样式可以放在同一级。 &#xff08;2&#xff09;必须设置唯一key进行刷新数据&#xff0c;使用v-show来展示每次渲染的组件数量。 <tran…...

详解Tomcat下载安装以及IDEA配置Tomcat(2023最新)

目录 步骤一&#xff1a;首先确认自己是否已经安装JDK步骤二&#xff1a;下载安装Tomcat步骤三&#xff1a;Tomcat配置环境变量步骤四&#xff1a;验证Tomcat配置是否成功步骤五&#xff1a;为IDEA配置Tomcat 步骤一&#xff1a;首先确认自己是否已经安装JDK jdk各版本通用安…...

Docker快速使用指南

docker pull ubuntu:22.04 //先拉取一个基础镜像&#xff0c;一般是操作系统创建一个Dockerfile&#xff0c;放在任意目录下&#xff0c;内容如下 # 使用 Ubuntu 22.04 作为基础镜像 FROM ubuntu:22.04# 设置环境变量&#xff0c;避免安装过程中出现交互提示 ENV DEBIAN_FRONT…...

【Project】基于Prometheus监控docker平台

一、设计背景 1.1项目简介 本项目旨在创建一个全面的容器化应用程序监控解决方案&#xff0c;基于Prometheus监控Docker平台上的各种服务。在当今的软件开发环境中&#xff0c;容器化技术已成为一种关键的工具&#xff0c;使应用程序能够更快速、可靠地交付和扩展。然而&…...

Binder通信协议

目录 一,整体架构 二,Binder通信协议 三&#xff0c;binder驱动返回协议 四&#xff0c;请求binder驱动协议 一,整体架构 二,Binder通信协议 三&#xff0c;binder驱动返回协议 binder_driver_return_protocol共包含18个命令&#xff0c;分别是&#xff1a; 四&#xff0c…...

使用 Postman 访问 Keycloak 端点

1. 引言 在本教程中&#xff0c;我们将首先快速回顾 OAuth 2.0、OpenID 和 Keycloak。然后&#xff0c;我们将了解 Keycloak REST API 以及如何在 Postman 中调用它们。 2. OAuth 2.0 OAuth 2.0 是一个授权框架&#xff0c;它允许经过身份验证的用户通过令牌向第三方授予访问…...

uniapp-X 对象动态取值

有个对象&#xff0c;例如 const data{age:12,list:[1,2,3,4]} 有个函数如下 export function getValueByPath(obj:UTSJSONObject, path:string):any {const current obj.getAny(path) as any;// 返回最终的值return current; } 期待 通过执行getValueByPath("xx.xx…...

建模软件Blender与Blender GIS插件安装教程

Blender&#xff08;blender.org - Home of the Blender project - Free and Open 3D Creation Software&#xff09;是一款功能强大的开源3D创作套件&#xff0c;它支持整个3D管道—建模、渲染、动画制作、模拟、渲染、合成和运动跟踪&#xff0c;甚至视频编辑和游戏制作&…...

数据解析与处理

数据解析与处理是数据科学、分析或开发中的核心步骤&#xff0c;涉及从原始数据中提取、清洗、转换和存储有效信息的过程。 一、数据解析 数据解析就是将原始数据&#xff08;如文本、二进制、日志、API响应等&#xff09;转换为结构化格式&#xff08;如表格、字典、JSON等&…...

强化学习概览

强化学习的目标 智能体&#xff08;Agent&#xff09;通过与环境&#xff08;Environment&#xff09;交互&#xff0c;学习最大化累积奖励&#xff08;Cumulative Reward&#xff09;​的策略。 数学抽象 马尔科夫决策过程&#xff08;MDP&#xff09; 收益 由于马尔科夫决…...

如何在netlify一键部署静态网站

1. 准备你的项目 确保你的静态网站文件&#xff08;如 HTML、CSS、JavaScript、图片等&#xff09;都在一个文件夹中。通常&#xff0c;项目结构如下&#xff1a; my-static-site/ ├── index.html ├── styles/ │ └── styles.css └── scripts/└── script.js…...

2024中国信通院“集智”蓝皮书合集(附下载)

【目 录】 1. 数字政府一体化建设蓝皮书&#xff08;2024年&#xff09; 2. 数字乡村发展实践蓝皮书&#xff08;2023年&#xff09; 3. 中国工业互联网发展成效评估报告&#xff08;2024年&#xff09; 4. 云计算蓝皮书&#xff08;2024年&#xff09; 5. 具身智能发展报告…...

springboot单机支持1w并发,需要做哪些优化

Spring Boot单机如何支持1万并发&#xff0c;需要做哪些优化。 首先&#xff0c;我得回想一下Spring Boot处理高并发的关键点在哪里。可能涉及到多个层面&#xff0c;比如Web服务器配置、数据库优化、代码层面的调整&#xff0c;还有JVM调优之类的。 首先&#xff0c;用户可能…...

HBuilderx 插件开发变量名称翻译 ,中文转(小驼峰,大驼峰,下划线,常量,CSS类名)

HBuilderx 插件开发变量名称翻译 &#xff0c;中文转&#xff08;小驼峰&#xff0c;大驼峰&#xff0c;下划线&#xff0c;常量&#xff0c;CSS类名&#xff09; 插件开发文档 工具HBuilderx &#xff0c;创建项目 创建成功后目录 插件需求 开发时 用来将中文转为&#xff0…...

岳阳市美术馆预约平台(小程序论文源码调试讲解)

第4章 系统设计 一个成功设计的系统在内容上必定是丰富的&#xff0c;在系统外观或系统功能上必定是对用户友好的。所以为了提升系统的价值&#xff0c;吸引更多的访问者访问系统&#xff0c;以及让来访用户可以花费更多时间停留在系统上&#xff0c;则表明该系统设计得比较专…...

C++ | 高级教程 | 文件和流

&#x1f47b; 概念 文件流输出使用标准库 fstream&#xff0c;定义三个新的数据类型&#xff1a; 数据类型描述ofstream输出文件流&#xff0c;用于创建文件并向文件写入信息。ifstream输入文件流&#xff0c;用于从文件读取信息。fstream文件流&#xff0c;且同时具有 ofst…...

Starlink卫星动力学系统仿真建模第九讲-滑模(SMC)控制算法原理简介及卫星控制应用

滑模控制&#xff08;Sliding Mode Control&#xff09;算法详解 一、基本原理 滑模控制&#xff08;Sliding Mode Control, SMC&#xff09;是一种变结构控制方法&#xff0c;通过设计一个滑模面&#xff08;Sliding Surface&#xff09;&#xff0c;迫使系统状态在有限时间内…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...