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

【第86期】CPU 空闲时在干嘛?

e161b94b166aaece58d72f579e7c8c5e.gif

人空闲时会发呆会无聊,计算机呢?

假设你正在用计算机浏览网页,当网页加载完成后你开始阅读,此时你没有移动鼠标,没有敲击键盘,也没有网络通信,那么你的计算机此时在干嘛?

有的同学可能会觉得这个问题很简单,但实际上,这个问题涉及从硬件到软件、从 CPU 到操作系统等一系列环节,理解了这个问题你就能明白操作系统是如何工作的了。

你的计算机 CPU 使用率是多少?

如果此时你正在计算机旁,并且安装有 Windows 或者 Linux ,你可以立刻看到自己的计算机 CPU 使用率是多少。

这是博主的一台安装有 Win10 的笔记本:

29ac44270010276c70e08d3fc08fcf39.png

可以看到大部分情况下 CPU 利用率很低,也就在 8% 左右,而且开启了 283 个进程,这么多进程基本上无所事事都在等待某个特定事件来唤醒自己,就好比你写了一个打印用户输入的程序,如果用户一直不按键盘,那么你的进程就处于这种状态。

有的同学可能会想也就你的比较空闲吧,实际上大部分个人计算机 CPU 使用率都差不多这样(排除掉看电影、玩游戏等场景),如果你的使用率总是很高,风扇一直在嗡嗡的转,那么不是软件 bug 就有可能是病毒。。。

那么有的同学可能会问,剩下的 CPU 时间都去哪里了?

剩下的 CPU 时间去哪里了?

这个问题也很简单,还是以 Win10 为例,打开任务管理器,找到 “详细信息” 这一栏,你会发现有一个 “系统空闲进程”,其 CPU 使用率达到了 99%,正是这个进程消耗了几乎所有的 CPU 时间。

230d011fd6a692d62e792db9d4633fed.png

那么为什么存在这样一个进程呢?以及这个进程什么时候开始运行呢?

这就要从操作系统说起了。

程序、进程与操作系统

当你用最喜欢的代码编辑器编写代码时,这时的代码不过就是磁盘上的普通文件,此时的程序和操作系统没有半毛钱关系,操作系统也不认知这种文本文件。

4971dc9acde9873befb70c8d138e2790.png

程序员写完代码后开始编译,这时编译器将普通的文本文件翻译成二进制可执行文件,此时的程序依然是保存在磁盘上的文件,和普通没有本质区别。

588bf2f95174b4a0b194adcfb70b30ca.png

但此时不一样的是,该文件是可执行文件,也就是说操作系统开始 “懂得” 这种文件,所谓 “懂得” 是指操作系统可以识别、解析、加载,因此必定有某种类似协议的规范,这样编译器按照这种协议生成可执行文件,操作系统就能加载了。

在 Linux 下可执行文件格式为 ELF ,在 Windows 下是 EXE 。

此时虽然操作系统可以识别可执行程序,但如果你不去双击一下(或者在Linux下运行相应命令)的依然和操作系统没有半毛钱关系。

但是当你运行可执行程序时魔法就出现了。

此时操作系统开始将可执行文件加载到内存,解析出代码段、数据段等,并为这个程序创建运行时需要的堆区栈区等内存区域,此时这个程序在内存中就是这样了:

2026917292d6edb2c865927a8cc5d250.png

最后,根据可执行文件的内容,操作系统知道该程序应该执行的第一条机器指令是什么,并将其告诉 CPU ,CPU 从该程序的第一条指令开始执行,程序就这样运行起来了。

一个在内存中运行起来的程序显然和保存在磁盘上的二进制文件是不一样的,总的有个名字吧,根据“弄不懂原则”,这个名字就叫进程,英文名叫做Process。

我们把一个运行起来的程序叫做进程,这就是进程的由来

此时操作系统开始掌管进程,现在进程已经有了,那么操作系统是怎么管理进程的呢?

调度器与进程管理

银行想必大家都去过,实际上如果你仔细观察的话银行的办事大厅就能体现出操作系统最核心的进程管理与调度。

首先大家去银行都要排队,类似的,进程在操作系统中也是通过队列来管理的。

同时银行还按照客户的重要程度划分了优先级,大部分都是普通客户;但当你在这家银行存上几个亿时就能升级为 VIP 客户,优先级最高,每次去银行都不用排队,优先办理你的业务。

类似的,操作系统也会为进程划分优先级,操作系统会根据进程优先级将其放到相应的队列中供调度器调度。

67244c0a7d3b7b605e60112ae4a720de.png

这就是操作系统需要实现的最核心功能。

现在准备工作已经就绪。

接下来的问题就是操作系统如何确定是否还有进程需要运行。

队列判空:一个更好的设计

从上一节我们知道,实际上操作系统是用队列来管理进程的,那么很显然,如果队列已经为空,那么说明此时操作系统内部没有进程需要运行,这是 CPU 就空闲下来了,此时,我们需要做点什么,就像这样:

if (queue.empty()) {
  do_someting();
}

这些编写内核代码虽然简单,但内核中到处充斥着 if 这种异常处理的语句,这会让代码看起来一团糟,因此更好的设计是没有异常,那么怎样才能没有异常呢?

很简单,那就是让队列永远不会空,这样调度器永远能从队列中找到一个可供运行的进程。

而这也是为什么链表中通常会有哨兵节点的原因,就是为了避免各种判空,这样既容易出错也会让代码一团糟。

e704e3217609f488b8c3cd7e110d1001.png

就这样,内核设计者创建了一个叫做空闲任务的进程,这个进程就是Windows 下的我们最开始看到的“系统空闲进程”,在 Linux 下就是第 0号进程。

当其它进程都处于不可运行状态时,调度器就从队列中取出空闲进程运行,显然,空闲进程永远处于就绪状态,且优先级最低

既然我们已经知道了,当系统无所事事后开始运行空闲进程,那么这个空闲进程到底在干嘛呢?

这就需要硬件来帮忙了。

一切都要归结到硬件

在计算机系统中,一切最终都要靠 CPU 来驱动,CPU 才是那个真正干活的。

0450de741c322c113fe81238fc2796a2.png

原来,CPU 设计者早就考虑到系统会存在空闲的可能,因此设计了一条机器指令,这个机器指令就是 halt 指令,停止的意思。

这条指令会让部分CPU进入休眠状态,从而极大减少对电力的消耗,通常这条指令也被放到循环中执行,原因也很简单,就是要维持这种休眠状态。

值得注意的是,halt 指令是特权指令,也就是说只有在内核态下 CPU 才可以执行这条指令,程序员写的应用都运行在用户态,因此你没有办法在用户态让 CPU 去执行这条指令。

此外,不要把进程挂起和 halt 指令混淆,当我们调用 sleep 之类函数时,暂停运行的只是进程,此时如果还有其它进程可以运行那么 CPU 是不会空闲下来的,当 CPU 开始执行halt指令时就意味着系统中所有进程都已经暂停运行。

软件硬件结合

现在我们有了 halt 机器指令,同时有一个循环来不停的执行 halt 指令,这样空闲任务进程的实际上就已经实现了,其本质上就是这个不断执行 halt 指令的循环,大功告成。

这样,当调度器在没有其它进程可供调度时就开始运行空间进程,也就是在循环中不断的执行 halt 指令,此时 CPU 开始进入低功耗状态。

56db21cec821e31f49a5cf8971acf564.png

在 Linux 内核中,这段代码是这样写的:

while (1) {
  while(!need_resched()) {
      cpuidle_idle_call();
  }
}

其中 cpuidle_idle_call函数最终会执行 halt 指令,注意,这里删掉了很多细节,只保留最核心代码,实际上 Linux 内核在实现空闲进程时还要考虑很多很多,不同类型的 CPU 可能会有深睡眠浅睡眠之类,操作系统必须要预测出系统可能的空闲时长并以此判断要进入哪种休眠等等,但这并不是我们关注的重点。

总的来说,这就是计算机系统空闲时 CPU 在干嘛,就是在执行这一段代码,本质上就是 CPU 在执行 halt 指令。

实际上,对于个人计算机来说,halt 可能是 CPU 执行最多的一条指令,全世界的 CPU 大部分时间都用在这条指令上了,是不是很奇怪。

更奇怪的来了,有的同学可能已经注意到了,上面的循环可以是一个while(1) 死循环,而且这个循环里没有break语句,也没有return,那么操作系统是怎样跳出这个循环的呢

关于这个问题,我们将会在后续文章中讲解。

总结

CPU 空闲时执行特定的 halt 指令,这看上去是一个很简单的问题,但实际上由于 halt 是特权指令,只有操作系统才可以去执行,因此 CPU 空闲时执行 halt 指令就变成了软件和硬件相结合的问题。

操作系统必须判断什么情况下系统是空闲的,这涉及到进程管理和进程调度,同时,halt 指令其实是放到了一个 while 死循环中,操作系统必须有办法能跳出循环,所以,CPU 空闲时执行 halt 指令并没有看上去那么简单。

希望这篇文章对大家理解 CPU 和操作系统有所帮助。

f97e5970a0262ee7b24262b56258044f.png

推荐阅读

b5275871ec834595fbfc529b3b745a47.png

CPU设计实战

f7689d285a0d1b01c9f7f8b278c586bd.png

作者:汪文祥邢金璋

龙芯中科技术股份有限公司首席工程师汪文祥作品

一本书带你从零开始设计自己的CPU

推荐语:深入剖析CPU设计与开发的关键环节;从零开始构建一个功能逐步完善的CPU;全面培养CPU设计的工程化思维与实战能力。

本书作者从事CPU产品自主研发工作近20年,在CPU设计方面积累了丰富的经验,并一直尝试在教学过程中将这些经验转化为教学内容,探索一条培养CPU设计人才的行之有效的途径。本书面向初学者,以实战的方式带领读者了解CPU设计的流程,并从零开始逐步开发出自己的CPU。本书将计算机组成与体系结构的理论知识和工业实践充分结合,使读者在实际的CPU设计与开发过程中更加深入地理解计算机系统的工作原理,掌握CPU设计理念、方法和技术。

3cfaa4b9edbb00f81609c818e7786edb.png

计算机体系结构基础(第3版 )

87feddf3681a26cb3af4bcabeaf1cffe.png

作者:胡伟武等

龙芯中科胡伟武领衔撰写

龙芯开源LoongArch版,学会造计算机!

从硬件工程师的角度理解软件,从软件工程师的角度理解硬件!

推荐语:本书由国内从事微处理器设计的一线科研人员编写而成。作者从微处理器设计的角度出发,充分考虑计算机体系结构的学科完整性,强调体系结构、基础软件、电路和器件的融会贯通。全书共分12章,包括指令系统结构、计算机硬件结构、CPU微结构、并行处理结构、计算机性能分析等主要内容,重点放在作为软硬件界面的指令系统结构,以及包含CPU、GPU、南北桥协同的计算机硬件结构上。

fef5c754118d8d695a68758757b679a2.png

现代操作系统:原理与实现 

3e0e9917c233e8d3ed6261a52ab1d16c.png

作者:陈海波、夏虞斌等

陈海波作品,结合前沿研究与工业界实践,面向真实场景与真实问题

全新打造ChcCore微内核系列课程实验,建立对操作系统的第一手实践经验

推荐语:操作系统和系统安全领域国际知名学者、上海交通大学陈海波、夏虞斌领衔撰写。由浅入深介绍现代操作系统经典理论与方法。本书以三个“面向”为导向,即面向经典基础理论与方法,面向国际前沿研究,面向工业界实践,深入浅出地介绍操作系统的理论、架构、设计方法与具体实现。本书是首本以ARM64为主体介绍操作系统的教材,将学术前沿与工业实践充分结合,不仅介绍了现有的Linux宏内核操作系统架构,而且介绍了微内核、外核等操作系统架构。

91e6cdad892b73de69b77a29c261e03d.png

计算机系统解密:从理解计算机到编写高效代码 

41bc2398d5b9e0ff2a4b2afc1443a34b.png

作者:[美]乔纳森·E.斯坦哈特(Jonathan E. Steinhart )

译者:张开元、张淼

计算机程序硬件软件从底层实现到高层展现原理讲解

对底层知识的多个主题进行了公平的覆盖

推荐语:计算机编程不是抽象的,程序是在机器上运行的。了解计算机如何工作以及程序如何在计算机上运行是成为一名更好的程序员的必要条件。在本书中,资深工程师Jonathan E. Steinhart深入探讨了计算机背后的基础概念,比如计算机硬件,软件在硬件上的行为,如何编写高效的程序,计算机安全基础知识,以及在编写代码时需要考虑的现实问题。本书对底层知识的多个主题进行了公平的覆盖——介绍有助于提高整个系统质量的许多领域的知识(包括计算机硬件、组合逻辑、时序逻辑、计算机体系结构、计算机组成原理、操作系统、系统程序设计等)。

54ee94c1bbc06f137fb30759e63db54e.png

深入理解计算机系统(原书第3版)

db4beea088296e016ecf633bfbd05490.png

作者:[美] 兰德尔 E.布莱恩特(Randal E. Bryant)

大卫 R. 奥哈拉伦(David R. O'Hallaron)

译者:龚奕利 贺莲

将所有计算机系统相关知识融会贯通

助你成为凤毛麟角的高级程序员的必备神书

如果你研究和领会了这本书里的概念,你将开始成为极少数的“牛人”!

本书是一本将计算机软件和硬件理论结合讲述的经典教程,内容覆盖计算机导论、体系结构和处理器设计等多门课程。卡内基-梅隆大学、北京大学、上海交大等国内外众多知名高校选用指定教材。本书的最大优点是为程序员描述计算机系统的实现细节,通过描述程序是如何映射到系统上,以及程序是如何执行的,使读者更好地理解程序的行为,以及造成效率低下的原因。从程序员的角度来学习计算机系统是如何工作的会非常有趣。最理想的学习方法是在真正的系统上解决具体的问题,或是编写和运行程序。这个主题观念贯穿本书始终。

第085期赠书活动中奖名单公布

d9675d26654a17af2a55431d591cd2f2.png

c67b0e9b311a7007191d76f33478ef60.png

赠书规则

送书规则:感谢大家对华章图书的信任与支持。在留言区谈谈你想要哪本书及理由。小编会在留言池随机捞2条锦鲤,分别包邮送出1本正版书籍。以上图书可任选一本。

截止日期:12月31日下午17:00

特别注意

1、请按规则结合自身工作与学习的经历留言请规避百度式名词解释式言论,走心留言优先。

2、阅读最多、分享最多者优先。参与活跃者优先。同一人每月最多获赠一本书。

特别说明:本活动无任何内幕,最终解释权归华章公司所有。

6eaf0de5a3c09cea639e9ca2bbd14c85.gif

b1654c5cb0a1fc3f08f06bcb919f8ee0.png

扫码关注【华章计算机】视频号

每天来听华章哥讲书

0be4ef616d0b358160a658fb53181e43.gif

更多精彩回顾

书讯 | 12月书讯(上) | 冬夜寒冷,读书暖心,华章科技上新啦!

书讯 | 12月书讯(下) | 冬夜寒冷,读书暖心,华章科技上新啦!

资讯 | 2022年六大值得关注的边缘计算趋势

书单 | 8本书助你零基础转行数据分析岗

干货 | 胡伟武:中国IT产业的根本出路在于构建自己新的体系

收藏 | Excel摸鱼技巧:快速实现分列转到行

上新 | 【新书速递】Django3.0应用开发详解

88877fe4e13112db18d0cb3abbe72161.gif

相关文章:

  • 机器学习的挑战:黑盒模型正面临这3个问题
  • 数据治理项目失败,90%都是被这样搞垮的!
  • 6本书,读懂2022年最火的边缘计算
  • 详解数据分析体系构成框架
  • 【新书速递】金融领域可解释机器学习模型与实践
  • 说大话还是真实力,Rust 是被炒“火”的吗?
  • 用Python写了一个图像文字识别OCR工具
  • 解读数据工程、数据科学和机器学习都有什么区别?
  • 1月书讯(上)| 2022年的第一本书
  • Docker冲顶技术热词,微服务应用热度不减,中国云原生开发者真实现状如何?...
  • 重磅!达摩院发布2022十大科技趋势
  • Flink1.14.2发布,除了log4j漏洞你还需要关注什么?
  • 揭秘 vivo 如何打造千万级 DAU 活动中台
  • 终于有人把“可解释机器学习”讲明白了
  • 产品经理必读:用户场景分析的四要素
  • CAP理论的例子讲解
  • Django 博客开发教程 8 - 博客文章详情页
  • javascript面向对象之创建对象
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • jdbc就是这么简单
  • Js基础——数据类型之Null和Undefined
  • Lucene解析 - 基本概念
  • Making An Indicator With Pure CSS
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • Vue实战(四)登录/注册页的实现
  • 开发基于以太坊智能合约的DApp
  • 删除表内多余的重复数据
  • 实现简单的正则表达式引擎
  • 双管齐下,VMware的容器新战略
  • 线性表及其算法(java实现)
  • 一个JAVA程序员成长之路分享
  • 一个SAP顾问在美国的这些年
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • ​渐进式Web应用PWA的未来
  • ​如何防止网络攻击?
  • # Apache SeaTunnel 究竟是什么?
  • # Panda3d 碰撞检测系统介绍
  • #QT项目实战(天气预报)
  • (1)(1.9) MSP (version 4.2)
  • (a /b)*c的值
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • .gitattributes 文件
  • .net core Swagger 过滤部分Api
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .NET连接MongoDB数据库实例教程
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • .project文件
  • [ 数据结构 - C++]红黑树RBTree
  • [Android实例] 保持屏幕长亮的两种方法 [转]
  • [boost]使用boost::function和boost::bind产生的down机一例