草庐IT

[面试直通版]操作系统核心之进程、线程与协程(下)

兔子队列 2025-07-09 原文

点击->操作系统复习的文章集<-点击

目录

操作系统线程

线程是什么

进程与线程的关系

用户态/内核态

操作系统资源管理

内核态

用户态

内核态/用户态切换

程序运行类型分析

计算密集型

IO密集型

结合进程,线程来理解

程序运行类型分析

协程基础

上下文切换

协程

协程为什么叫协作式线程?

协程的优缺点


  • 操作系统线程

  • 典型问题:
  • 简述进程和线程的区别
  • 以下内容带您一步步了解
  • 线程是什么

  • 比进程更小的独立运行的基本单位-线程(Threads)
  • 线程的提出主要是为了提高系统内程序并发执行的程度,从而进一步提升系统的吞吐量,充分发挥多核CPU的优越性而设计的
  • 引入进程是为了操作系统更加方便地管理程序,使得多个程序能并发管理和执行
  • 而线程则是为了减少程序在并发执行时的开销,并且提高程序内程序并发执行的程度
  • 从从属关系来看,一个进程对应多个线程,线程是从属于某一进程的
  • 线程的一大特点
  • 轻装上阵
  • 在一些地方称其为轻量级进程
  • 不管在调度,切换,运行都比进程更加轻量
  • 线程是操作系统进行运行调度的最小单位
  • 包含在进程之中,是进程中实际运行工作的单位
  • 一个进程可以并发多个线程,每个线程执行不同的任务
  • 线程强调的是运行
  • 进程强调的是资源分配
  • 进程与线程的关系

  • 进程的线程共享进程资源
  • 因为操作系统在进行资源分配时并不是以线程为单位的,而是以进程为单位
  • 线程本身是不拥有资源的
  • 用户态/内核态

  • 典型问题:
  • 简述操作系统的内核态
  • 简述进程什么时候进入内核态
  • 以下内容带您一步步了解
  • 操作系统资源管理

  • 有处理器资源,IO设备资源,存储器资源,文件资源等等
  • 这些资源都是交给操作系统去直接管理的,用户是不能直接接触到的,都是通过操作系统提供的接口来处理的
  • 为了屏蔽用户可能对计算机所造成的影响,操作系统就把操作系统的状态分为内核态和用户态2个部分
  • 关键的程序就运行在内核态
  • 用户所编写的程序在没有必要的情况下一般都是运行在用户态
  • 以Linux作为例子
  • Linux设计的哲学
  • 对不同的操作赋予不同的执行等级
  • 与系统相关的一些特别关键的操作必须由最高特权的程序来完成
  • 内核态

  • 内核是操作系统的内部核心程序,它向外部提供了对计算机设备的核心管理调用
  • 我们将操作系统的代码分成2部分
  • 内核所在的地址空间称作内核空间
  • 内核空间:存放的是内核代码和数据
  • 内核态一般指的是运行在内核空间的程序和代码的状态
  • 当执行到内核空间的一段代码时,我们称程序处于内核态
  • 内核态下的程序可以访问所有资源和设备
  • 用户态

  • 在内核以外的统称为外部管理程序,它们大部分是对外围设备的管理和界面操作
  • 外部管理程序与用户进程所占据的地址空间称为用户(外部)空间
  • 当程序执行到外部空间代码时,我们称程序处于用户态
  • 在此状态下,执行的代码被硬件限定,不能进行某些操作,以防止给操作系统带来安全隐患
  • 内核态/用户态切换

  • 从用户态切换到内核态主要有3种情况:
  • 系统调用
  • 操作系统管理资源时为我们提供了很多接口,通过这些接口就可以操作这些资源
  • 这些接口就可以理解为系统调用
  • 所有用户程序都是运行在用户态,但是有时候这些用户态的程序也需要做一些内核态的事情
  • 比如说从硬盘读取数据,从网卡里读写数据,这些都只能由操作系统来完成
  • 这时就要通过系统调用的操作来把这些工作交给操作系统去执行
  • 进行了系统调用后,当前用户程序就会由用户态切换到内核态去执行
  • 当系统调用完成后,会返回数据,用户态程序拿到数据后,它又返回到用户态来继续执行
  • 异常中断
  • 如CPU在执行用户态程序时突然发生了一些不可预知的事件如内存不存在,当前访问程序出现异常等
  • 异常只能由操作系统去管理,这时进程就会由用户态切换到内核态,让操作系统去处理相关异常事件
  • 外围设备中断
  • 在读写外围设备时,如果说外围设备在完成工作之后,它可以给CPU发出中断信号,可以暂停当前需要执行的指令,转而去执行中断信号对应的处理程序
  • 如暂停当前需要执行的指令的程序是用户态的程序的话,那么它处理外围设备中断时就会转为内核态去执行
  • 著名事件Intel meltdown漏洞
  • 就是由于通过漏洞跳过以上3种步骤进行了切换,越权,使得用户程序也可以拥有最高的执行权限
  • 程序运行类型分析

  • 典型问题:
  • 举例说明什么是IO密集型任务
  • IO密集型任务部署时,应该注意什么
  • 以下内容带您一步步了解
  • 计算密集型

  • 也称为CPU密集型
  • 完成一项任务的时间取决于CPU的速度
  • 特点:
  • CPU利用率高,并且运行时很可能导致别的程序处理慢的情况
  • 对处理器资源(高频使用)要求很高,对于其它资源(低频使用)要求较低
  • 计算1024000的阶乘就是典型的计算密集型的任务
  • IO密集型

  • 完成一项任务的时间取决于IO设备的速度
  • 特点:
  • 频繁读写网络、磁盘等任务都属于IO密集型任务
  • 即磁盘的读取数据和输出数据非常大的时候就属于IO密集型
  • CPU利用率低,大部分时间在等待设备完成
  • 这是由于IO操作的运行时间远远大于CPU、内存运行时间,所以任务的大部分时间都是在等待IO操作完成
  • 对存储器资源(高频使用)要求很高,对于其它资源(低频使用)要求较低
  • 往磁盘写入10G的文件就是个典型的IO密集型
  • 结合进程,线程来理解

  • 计算密集型
  • 计算密集型通过多线程的改造带来了很大的效率提升
  • 如计算1024000的阶乘,有个多核CPU
  • 如果是单进程单线程去运行还有其它核没有利用到
  • 这就要通过多线程才能充分利用CPU资源
  • 通过合理的设计把任务拆分给多个线程来提升效率
  • IO密集型
  • IO密集型通过多线程的改造带来不了很大的效率提升
  • 如往磁盘里写入10G的文件
  • 大部分时间都是在等待,都是在等存储器把数据写完成的
  • 在等待时间里,程序是处于阻塞的状态
  • 在阻塞状态程序并没有使用CPU而是被挂起了
  • 所以在这种情况下对程序进行多线程改造也不能很好地提升运行效率
  • 程序运行类型分析

  • 游戏画面渲染及很多数学操作,是典型的计算密集型任务
  • 复制粘贴本质上是对文件内容的复制,所以它是典型的IO密集型任务
  • 图片卷积处理是典型的计算密集型任务
  • 下载工具涉及到网络IO和磁盘IO,是典型的IO密集型任务
  • AI模型训练既属于计算密集型,也属于IO密集型,即混合密集型
  • 视频解码既要读,也要解码,既属于计算密集型,也属于IO密集型,即混合密集型
  • 协程基础

  • 典型问题:
  • 协程是什么?为什么需要协程
  • 多协程可以发挥多核CPU的优势吗?为什么?
  • 以下内容带您一步步了解
  • 上下文切换

  • 主要存在于分时系统里
  • Linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行(主要得益于多道程序设计)
  • 当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短的时间内,将CPU轮流分配给它们,造成多任务同时运行的错觉
  • 而在每个任务运行前,CPU都需要知道任务从哪里加载,又从哪里开始运行(上下文数据)
  • 有寄存器级上下文,用户级上下文,系统级上下文等等
  • 上下文切换过程
  • 1.准备就绪进程运行数据
  • 2.保存当前进程运行状态
  • 3.迁出当前进程数据
  • 4.迁入就绪进程数据
  • 5.恢复就绪进程上一次运行状态
  • 6.就绪进程开始运行
  • 切换会涉及到用户态和内核态的切换,它是通过系统调用来完成这个切换的
  • 每一次切换都需要一定时间,每秒钟切换次数还很高,是需要一定时间成本的
  • 协程

  • 在很多资料上也叫微线程,纤程以及协作式线程
  • 特点:
  • 比线程更小的粒度
  • 运行效率更高
  • 可以支持更高的并发
  • 正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程
  • 协程的本质是用户级线程
  • 线程更多指的是内核级线程,内核级线程是由操作系统内核提供的
  • 而协程(用户级线程)它是由用户态的程序提供的
  • 协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)
  • 协程为什么叫协作式线程?

  • 用户态的多个协程可以对应1个线程
  • 还因为协程本身只运行在用户态,并且它是由用户自行调度的,内核无法干涉
  • 协作运行,相互让步
  • 正常的程序逻辑是从上往下顺序执行的
  • 如果有协程的加入的话,就可以把这个逻辑拆为2个部分
  • 2者是相互让步的,它们并没有产生抢夺式的调度,而是主动让出CPU
  • 所以说它们是一个协作的关系
  • 协程的优缺点

  • 调度,切换,管理更加轻量
  • 不管是调度,切换,管理都并没有在内核态产生任何的操作
  • 比如调度是通过相互让步产生的,管理也是在用户态实现的
  • 内核无法感知协程的存在
  • 因为协程和线程之间是多对一的关系
  • 内核只能感知到线程,因为线程的数据结构是维护在内核的
  • 但是因为协程是在用户态,内核无法感知
  • 所以说协程调度出了什么问题的话,内核也没有办法去干预
  • 设计体现
  • 可以减少上下文切换的成本
  • 内核无法感知到协程存在,CPU内核只能感知到线程,只能对线程进行调度,因此协程是无法发挥CPU的多核优势
  • 主要运用在多IO的场景(比如说高并发的用户接入)

有关[面试直通版]操作系统核心之进程、线程与协程(下)的更多相关文章

  1. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  2. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  5. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  6. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  7. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  8. ruby - 如何让Ruby捕获线程中的语法错误 - 2

    我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

  9. ruby - 如何在 ruby​​ 中运行后台线程? - 2

    我是ruby​​的新手,我认为重新构建一个我用C#编写的简单聊天程序是个好主意。我正在使用Ruby2.0.0MRI(Matz的Ruby实现)。问题是我想在服务器运行时为简单的服务器命令提供I/O。这是从示例中获取的服务器。我添加了使用gets()获取输入的命令方法。我希望此方法在后台作为线程运行,但该线程正在阻塞另一个线程。require'socket'#Getsocketsfromstdlibserver=TCPServer.open(2000)#Sockettolistenonport2000defcommandsx=1whilex==1exitProgram=gets.chomp

  10. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

随机推荐