操作系统内功篇:硬件结构之CPU是如何执行任务的?

一 CPU是如何读写数据的?

1.1 CPU架构(组成)

当代CPU一般是多核心的,每个核心都有自己的一个L1和L2Cache,L3Cache是一个CPU所有核心共享的,一个CPU只有一个。L1Cache分为数据缓存和指令缓存。

CPU有三层高速缓存的目的就是将Cache作为CPU和内存间的缓存层,减少CPU访问内存的频率从而提高效率。 CPU从内存读取数据也是先读取到Cache,一次读取是读取一个Cache Line(缓存行)。所以说缓存行是CPU读取数据的最小单位。Cache Line的大小可以在Linux系统中查看和修改,默认是64byte。

所以说我们访问内存时候尽量按照物理内存地址数据的时候,尽量顺序访问,这样就可以命中率高,从而提高效率。

1.2 CPU伪共享问题

先介绍一下什么是伪共享问题?

多线程因为同时读写同一个CacheLine的不同变量时导致失效的现象。

假设现在有一个双核心CPU,这两个CPU核心并行运行两个不同的线程,同时从内存中读取两个不同的数据,分别是类型为 long 的变量 A 和 B,这个两个数据的地址在物理内存上是连续的,如果 Cahce Line 的大小是 64 字节,并且变量 A 在 Cahce Line 的开头位置,那么这两个数据是位于同一个 Cache Line 中,又因为 CPU Line 是 CPU 从内存读取数据到 Cache 的单位,所以这两个数据会被同时读入到了两个 CPU 核心中各自 Cache 中。 如果这两个不同核心的线程分别修改不同的数据,比如 1 号CPU 核心的线程只修改了 变量 A,或 2 号 CPU 核心的线程的线程只修改了变量 B,会发生什么呢? 结合保证多核缓存一致的 MESI 协议,来说明这一整个的过程:

●①.最开始变量 A 和 B 都还不在 Cache 里面,假设 1 号核心绑定了线程 A,2 号核心绑定了线程 B,线程 A 只会读写变量 A,线程 B 只会读写变量 B。

●②1 号核心读取变量 A,由于 CPU 从内存读取数据到 Cache 的单位是 Cache Line,也正好变量 A 和 变量 B 的数据归属于同一个 Cache Line,所以 A 和 B 的数据都会被加载到 Cache,并将此 Cache Line 标记为「独占」状态。

●③接着,2 号核心开始从内存里读取变量 B,同样的也是读取 Cache Line 大小的数据到 Cache 中,此 Cache Line 中的数据也包含了变量 A 和 变量 B,此时 1 号和 2 号核心的 Cache Line 状态变为「共享」状态。

●④1 号核心需要修改变量 A,发现此 Cache Line 的状态是「共享」状态,所以先需要通过总线广播发送消息给 2 号核心,通知 2 号核心把 Cache 中对应的 Cache Line 标记为「已失效」状态,然后 1 号核心对应的 Cache Line 状态变成「已修改」状态,并且修改变量 A。

●⑤之后,2 号核心需要修改变量 B,此时 2 号核心的 Cache 中对应的 Cache Line 是已失效状态,另外由于 1 号核心的 Cache 也有此相同的数据,且状态为「已修改」状态,所以要先把 1 号核心的 Cache 对应的 Cache Line 写回到内存,然后 2 号核心再从内存读取 Cache Line 大小的数据到 Cache 中,最后把变量 B 修改到 2 号核心的 Cache 中,并将状态标记为「已修改」状态。

所以,可以发现如果 1 号和 2 号 CPU 核心这样持续交替的分别修改变量 A 和 B,就会重复 ④ 和 ⑤ 这两个步骤,Cache 并没有起到缓存的效果,虽然变量 A 和 B 之间其实并没有任何的关系,但是因为同时归属于一个 Cache Line ,这个 Cache Line 中的任意数据被修改后,都会相互影响,从而出现 ④ 和 ⑤ 这两个步骤。

1.3 避免伪共享解决方案

所以为了避免出现伪共享的问题就得让数据避免出现在一个Cache Line。 Linux中为了防止出现这种问题是采用了宏定义的方案,定义一个宏来指定变量的对齐方式,确保变量被存储在不同的缓存行中,避免不必要的缓存行竞争。具体不赘述。

常用的解决伪共享问题的方案还有使用缓存行填充和缓存行隔离技术。

二 CPU如何选择线程?

2.1 进程和线程

进程是分配资源的基本单位,也是调度的基本单位。 进程有自己的PCB,线程有自己的TCB,TCB们用链表管理起来被置在PCB中。本质都是一个结构体,存储着一些变量。不过线程的资源都是用的把这个线程创建出来的进程的资源。所以线程又名轻量级进程。没有创建线程的进程,是只有单个执行流的,被称为主线程。主线程可以创建子线程(工作线程)。

2.2 普通任务和实时任务

Linux中,根据调度进程的优先级和响应要求,优先级数值越小,优先级越高。将调度进程分为两类:

●①实时任务:对系统的响应时间要求很高,要求尽快被执行,优先级在0~99。

●②对响应速度没太大的要求,优先级在100~139。

2.3 调度类

调度类通常是指负责任务调度和资源管理的一个类。调度类通常包含了各种方法和属性,用于实现任务的调度、资源的分配以及执行控制。

调度器是计算机系统中的一个重要组件,其作用是协调和管理系统资源的分配,以实现对任务和进程的调度和执行。

Linux为了保证高优先级的进程能够尽早的被执行,于是有了几种调度类:Deadline/Realtime/Fair Deadline和Realtime这两个调度类都是用于实时任务,这两个调度类的策略策略有三种。

Deadline的调度策略是sched_deadline。Deadline的调度器是Deadline调度器。

Realtime的调度策略是sched_fifo和sched_rr。Realtime的调度器是RT调度器。

Fair的调度策略是sched_normal和sched_batch。调度器是CFS调度器。

Deadline和Realtime是用于实时任务,Fair是用于普通任务。

2.4 完全公平调度

我们平日里遇到的基本都是普通任务,对于普通任务来说,公平性最重要,在 Linux 里面,实现了一个基于 CFS 的调度算法,也就是完全公平调度。

●这个算法的理念是想让分配给每个任务的 CPU 时间是一样,于是它为每个任务安排一个虚拟运行时间 vruntime,如果一个任务在运行,其运行的越久,该任务的 vruntime 自然就会越大,而没有被运行的任务,vruntime 是不会变化的。

●那么,在 CFS 算法调度的时候,会优先选择 vruntime 少的任务,以保证每个任务的公平性。

●这就好比,让你把一桶的奶茶平均分到 10杯奶茶杯里,你看着哪杯奶茶少,就多倒一些;哪个多了,就先不倒,这样经过多轮操作,虽然不能保证每杯奶茶完全一样多,但至少是公平的。

●当然,上面提到的例子没有考虑到优先级的问题,虽然是普通任务,但是普通任务之间还是有优先级区分的,所以在计算虚拟运行时间 vruntime 还要考虑普通任务的权重值,注意权重值并不是优先级的值,内核中会有一个 nice 级别与权重值的转换表,nice 级别越低的权重值就越大。所以虚拟运行时间(vruntime)+=实际运行时间*nice_0_load/权重,可以不用管 nice_0_load 是什么,就认为它是一个常量,那么在「同样的实际运行时间」里,高权重任务的 vruntime 比低权重任务的 vruntime 少,你可能会奇怪为什么是少的?你还记得 CFS 调度吗,它是会优先选择 vruntime 少的任务进行调度,所以高权重的任务就会被优先调度了,于是高权重的获得的实际运行时间自然就多了。

2.5 CPU运行队列

一个系统通常都会运行着很多任务(任务就是进程),多任务的数量基本都是远超 CPU 核心数量,因此这时候就需要排队。

事实上,每个 CPU 都有自己的运行队列,用于描述在此 CPU 上所运行的所有进程,其队列包含三个运行队列,Deadline 运行队列 、实时任务运行队列 和 CFS 运行队列 ,优先级Deadline > Realtime > Fair,这意味着 Linux 选择下一个任务执行的时候,会按照此优先级顺序进行选择,也就是说先从 Deadline运行队列里选择任务,然后从 实时任务运行队列里选择任务,最后从 CFS运行队列里选择任务。因此,实时任务总是会比普通任务优先被执行。

2.6 调度优先级

如果我们启动任务的时候,没有特意去指定优先级的话,默认情况下都是普通任务,在Linux系统中,默认情况下,如果没有特意指定任务的优先级,则新创建的任务通常会被视为普通任务。这些普通任务将按照默认的调度策略和调度参数来进行调度。普通任务的调度类是 Fail,由 CFS 调度器来进行管理。CFS 调度器的目的是实现任务运行的公平性,也就是保障每个任务的运行的时间是差不多的。

如果你想让某个普通任务有更多的执行时间,可以调整任务的 nice 值,从而让优先级高一些的任务执行更多时间。nice 的值能设置的范围是 -20~19, 值越低,表明优先级越高,因此 -20 是最高优先级,19 则是最低优先级,默认优先级是 0。nice 值并不是表示优先级,而是表示优先级的修正数值,它与优先级的关系是这样的:priority(new) = priority(old) + nice。内核中,priority 的范围是 0~139,越低,优先级越高,其中前面的 0~99 范围是提供给实时任务使用的,而 nice 值是映射到 100~139,这个范围是提供给普通任务用的,因此 nice 值调整的是普通任务的优先级。

在前面我们提到了,权重值与 nice 值的关系的,nice 值越低,权重值就越大,计算出来的 vruntime 就会越少,由于 CFS 算法调度的时候,就会优先选择 vruntime 少的任务进行执行,所以 nice 值越低,任务的优先级就越高。

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

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

相关文章

有什么小程序适合个人开发?

在这个信息爆炸的时代,小程序已经成为了我们生活中的一部分。无论是出行、购物还是娱乐,小程序都能为我们提供便捷的服务。对于个人开发者来说,开发一个小程序不仅可以锻炼自己的技术能力,还可以为他人提供便利,甚至有…

AndroidStudio开发 相关依赖

1、com.google.zxing 用于二维码扫描 2、butterknife 用于简化findView 和 onClick操作 3、pub.devrel:easypermissions 简化权限请求的库 4、 网络请求框架(一):android-async-http 网络请求框架(二):xUtils 网络请求框架(三):Volley Volley…

安装paddle detection心得

一、安装PaddlePaddle conda create -n mypaddle python3.8 conda activate mypaddle python -m pip install paddlepaddle-gpu2.6.0 -i https://mirror.baidu.com/pypi/simple 请确保您的PaddlePaddle安装成功并且版本不低于需求版本。使用以下命令进行验证。 这是CUDA1…

Warning logs 2024-03-23

给旧的笔记本安装ubuntu系统,并实现ssh远程连接 1、下载ubuntu系统 ubuntu下载链接 选择带桌面版本 2、准备U盘 3、使用UltraISO制作启动盘 破解UltraISO软件 输入 注册名:王涛 注册码:7C81-1689-4046-626F 使用UltraISO&#xff0c…

RabbitMQ的使用—实战

RabbitMQ的使用—实战 ​ RabbitMQ是一个开源的消息代理中间件,在分布式系统开发中被广泛应用。它实现了高级消息队列协议(AMQP),提供可靠的消息传递、灵活的路由、消息确认等功能。下面是使用RabbitMQ的基本流程: 安…

ECS Fargate 上部署 SkyWalking OAP Server:利用 AWS CLI 和服务发现提供服务

在本篇文章中,我们将演示如何使用 AWS CLI 在 ECS Fargate 上部署 SkyWalking OAP Server,并利用 AWS 服务发现为 gRPC 流量提供一个静态入口点。这样,客户端就可以通过服务发现名称访问 gRPC 服务。以下是详细步骤: 1. 注册任务定义 创建一个名为 ​​dev-skywalking-oa…

吴长江分红

吴长江是雷士照明的创始人,他在公司初创时与两位合伙人共同持有股份,但随着公司的发展,分红问题逐渐凸显。吴长江在面临分红分歧时,选择稀释自己的股份,将部分股份转让给其他股东,以实现股权的均衡。然而&a…

雷卯推荐超级省电防反接方案

方案特别适合一端电池,一端充电的防反接,特别节能 低VF肖特基电源防反接 此方案采用3颗低压降SKY,相比只用1颗功耗更低,可以防止元器件过热 (两者正常工作损耗对比公式: 1.采用1颗SS34LVFA:…

【MySQL数据库】二级内容整理

文章目录 前言基础知识题库软件考试建议总结前言 本文分享一些备考二级MySQL数据库程序设计的资料和心得,希望对同样复习MySQL数据库知识的小伙伴们能够有所帮助。⛽ 基础知识 如果有对MySQL完全不了解的同学可以从这里入门: 👉 MySQL系列视频如果觉得视频时间比较长,可以…

如何安装配置Goland并使用固定公网地址SSH远程连接本地服务器

文章目录 1. 安装配置GoLand2. 服务器开启SSH服务3. GoLand本地服务器远程连接测试4. 安装cpolar内网穿透远程访问服务器端4.1 服务器端安装cpolar4.2 创建远程连接公网地址 5. 使用固定TCP地址远程开发 本文主要介绍使用GoLand通过SSH远程连接服务器,并结合cpolar内…

八、C#计数排序算法

简介 计数排序是一种非比较性的排序算法,适用于排序一定范围内的整数。它的基本思想是通过统计每个元素的出现次数,然后根据元素的大小依次输出排序结果。 实现原理 首先找出待排序数组中的最大值max和最小值min。 创建一个长度为max-min1的数组count…

嵌入式学习第三十天!(单向链表练习)

1. 单向链表的逆序: int Is_Empty_Link(LINK_LIST *plist) {return plist->phead NULL; }void Reverse_Link(LINK_LIST *plist) {LINK_NODE *ptmp plist->phead;LINK_NODE *pinsert NULL;plist->phead NULL;if(Is_Empty_Link(plist)){return;}else{wh…

策略模式在项目中实际应用

Java策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。策略模式使得算法可以独立于使用它的客户端变化。在Java中实现策略模式,通常包含三个…

Vue3:编程式路由导航

一、情景说明 Vue3的用法略有区别 Vue2的用法&#xff1a;https://blog.csdn.net/Brave_heart4pzj/article/details/136326608 二、案例 简单理解&#xff1a;RouterLink中to怎么写&#xff0c;router.replace或router.push中就怎么配置。 <!-- 跳转的按钮 --> <…

IM系统设计之websocket消息转发

Websocket消息转发 项目地址&#xff1a;gitgithub.com:muyixiaoxi/Link.git 上周面试被面试官问到&#xff1a;“在分布式IM系统中&#xff0c;如何实现多个websocket集群之间的通信”。 我在思考了良久后回答&#xff1a;“不会”。 随着我的回答&#xff0c;我和面试官的…

企业产品网络安全建设实录日报规划

为什么要做这个系列&#xff1f; 因为太忙了&#xff0c;忙工作&#xff0c;忙家庭。很难再像之前一样能做到电脑前码一个小时的字&#xff0c;写半个小时的博客。 但是现在的经验增长快速&#xff0c;有很多值得分享的点 想想这平行世界里的我&#xff0c;实际上并不是每一个人…

Spring Data访问Elasticsearch----创建存储库实例

Spring Data访问Elasticsearch----创建存储库实例 一、Java配置二、XML配置三、使用过滤器四、独立使用 本文介绍如何为已定义的存储库接口创建实例和bean定义。 一、Java配置 在Java配置类上使用特定于存储的EnableElasticsearchRepositories注解来定义用于存储库激活的配置。…

MySQL 中的事务和存储引擎

目录 事务的 ACID 特性 MySQL 的四种隔离机制和问题 MySQL 的四种隔离机制&#xff1a; MySQL 的存储引擎 InnoDB 存储引擎 MyISAM 存储引擎 Memory 存储引擎 通过 ALTER TABLE 语句更改存储引擎 在创建表时指定存储引擎 通过修改配置文件设置默认存储引擎 在数据库系…

element el-dialog里再调用其他组件,查找不到组件的方法

需求描述&#xff1a;点击编辑按钮&#xff0c;跳出编辑弹窗&#xff0c;回显图片组件里面的图片问题&#xff1a;element el-dialog里再调用组件&#xff0c;打开该弹窗的瞬间找不到弹窗里调用子组件的方法原因&#xff1a;弹窗显示时&#xff0c;调用的子组件还没渲染出来所以…

【机器学习入门 】支持向量机

系列文章目录 第1章 专家系统 第2章 决策树 第3章 神经元和感知机 识别手写数字——感知机 第4章 线性回归 第5章 逻辑斯蒂回归和分类 前言 支持向量机(Support Vector Machine) 于1995年发表&#xff0c;由于其优越的性能和广泛的适用性&#xff0c;成为机器学习的主流技术&…