OS Review2 处理器管理

处理器状态

Intel x86特权等级

Intel x86的处理器状态有四个特权级别:0级权限最高,3级权限最低

  • 0级:内核级
    处理I/O操作、执行中断处理等关键操作
  • 1级:系统调用级
    可以执行系统调用,获得特定的和受保护的程序的服务
  • 2级:共享库级
    可被多个运行进程共享,允许调用库函数,读取但不修改相关数据
  • 3级:应用程序级
    所受到的保护最少

处理器状态及其转换

导致处理器从用户态向内核态转换的时机

  • 程序请求操作系统服务,执行系统调用
  • 程序运行时,产生中断,转向中断处理程序
  • 程序运行时,产生异常事件,转向异常处理程序

三类情况都通过中断机制发生

  • 中断和异常是从用户态到内核态转换仅有的途径
  • 计算机提供一条特权指令称作加载程序状态字(Intel x86为iret指令),用来实现从从内核态转向用户态,控制权交给应用进程

用户栈和核心栈

用户栈

  • 进程用户空间中开辟的一块区域,用于保存应用程序的子程序(函数)间相互调用的参数、返回值、返回点以及子程序的局部变量

核心栈

  • 也叫系统栈或内核栈,是内存中属于操作系统空间的一块区域
  • 一方面,用于保存中断现场,对于嵌套中断,被中断程序的现场信息依次压入核心栈,中断返回时逆序弹出
  • 另一方面,保存操作系统程序(函数)间相互调用的参数、返回值、返回点以及程序局部变量
  • 每个进程被创建时捆绑一个核心栈,具有可读可写不可执行属性

程序状态字

  • 用于将程序运行时的一组动态信息汇集在一起,用于实现程序状态的保护和恢复:
    控制指令执行顺序
    保留和指示与程序有关的系统状态
  • 每个程序都有一个与其执行相关的PSW,每个处理器都设置一个PSW寄存器:
    程序占有处理器执行时,它的PSW将占有PSW寄存器

中断技术

中断概念

  • 现代操作系统是由“中断驱动”的

  • 中断是指程序执行过程中,遇到急需处理的事件时,暂时中止CPU上现行程序的运行,转去执行相应的事件处理程序,待处理完成后再返回原程序被中断处或调度其他程序执行的过程

  • 在中断事件发生后,中断装置能改变处理器内操作的执行顺序

中断源分类

外中断(中断或异步中断):指来自处理器之外的中断信号

  • 外中断又分可屏蔽中断和不可屏蔽中断
  • 每个不同中断具有不同的中断优先级,表示事件的紧急程度,在处理高一级中断时,往往会屏蔽部分或全部低级中断

内中断(异常或同步中断):指来自处理器内部,通常由于程序执行中,发现与当前指令关联的、不正常的、或是错误的事件,内中断不可屏蔽

  • 访管中断:由执行系统调用而引起
  • 硬件故障中断:如电源失效、协处理器错误、奇偶校验错误、总线超时等
  • 程序性异常:如非法操作、地址越界、页面故障、调试指令、除数为0和浮点溢出等

中断VS异常:

  • 中断是由与现行指令无关的中断信号触发的(异步的),且中断的发生与CPU处在用户模式或内核模式无关,在两条机器指令之间才可响应中断,一般来说,中断处理程序提供的服务不是为当前进程所需的
  • 异常由CPU控制单元产生的,源于现行程序执行指令过程中检测到例外
  • 异常与CPU是同步的,允许指令在执行期间响应异常
  • 大部分异常发生在用户态,而内核态唯一发生的异常是“缺页异常”
  • 异常包括很多方面,有出错(fault),也有陷入(trap)等

“中断”要求被快速处理,以便及时响应其它中断信号,所以,中断处理程序处理过程中是不能阻塞的;
“异常”处于被打断的当前进程上下文中,所提供的服务是当前进程所需要的,所以,异常处理程序处理过程中是可以阻塞的
中断允许发生嵌套,但异常大多为一重;
异常处理过程中可能会产生中断,但中断处理过程中决不会被异常打断

中断和异常的响应及服务

  • 发现中断源
    在中断未被屏蔽前提下,硬件发现中断/异常事件,并由 CPU 响应中断/异常请求
    当发现多个中断源时,将根据预定的中断优先级先后响应中断请求
  • 保护现场
    暂停当前程序运行,硬件将中断点的现场信息(PSW)保存至核心栈
  • 转向处理中断/异常事件的处理程序
    此时处理器状态已从用户态切换至内核态,中断/异常处理程序开始工作
  • 恢复现场
    当中断处理结束后,恢复原运行程序的PSW,重新返回中断点以便执行后续指令
    说明:异常处理结束后,返回点会因异常类型而异 。

中断事件处理原则

硬件故障中断

  • 需要人工干预,如复位、设置或替换。
  • 中断处理程序保护现场、停止设备工作,停止CPU运行、向操作员报告故障信息。

程序性中断

  • 语法错误、逻辑错误、异常 。
  • 不同用户处理要求不同,借助于信号机制将捕获中断事件,并原封不动地转交给应用程序自行处理 。

I/O中断

  • I/O操作正常结束
    把等待传输的下一个进程设置为就绪态,让它占有设备或通道并启动数据传输。
  • I/O操作发生故障
    先向设备发命令索取状态字,分析产生故障的确切原因,再进行复执或请求。人工干预
  • I/O操作发生异常
    分析情况采取相应措施,向操作员报告,如通知操作员换卷、装纸等。
  • 设备报到或设备结束
    表示有设备接入可供使用或设备断开暂停使用,操作系统应修改系统数据结构中相应设备的状态 。

访管中断

  • 由程序执行访管指令(包括操作码和访管参数 )引起,可看做机器指令的一种扩充 。
  • 机器在执行访管指令时,将访管参数作为中断字并入PSW,同时送入内存中指定单元,操作系统的访管中断处理程序分析访管参数、进行合法性检查后,按照访管参数具体要求进行相应处理 。

时钟中断

  • 时钟是操作系统进行调度工作的重要工具
  • 利用定时器能够确保操作系统在必要时获得控制权,陷入死循环的进程最终会因时间片耗尽而被迫让出处理器
  • 时钟可分成绝对时钟和间隔时钟两种,通常使用一个硬件时钟,按照固定周期发出中断请求
    绝对时钟寄存器:定时地把此寄存器的内容加1
    间隔时钟寄存器:通过程序设置此寄存器初值,在每个时间切换点将的内容减1,内容为0时产生间隔时钟中断

Linux的时钟中断

Linux系统运行不同的间隔定时器,类型有三种

  • real:间隔定时器按实际经过时间计时,不管进程处在何种模式下运行,包括进程被挂起时,计时总在进行,定时到达时发送给进程一个SIGALRM信号
  • virtual:间隔定时器进程在用户态下执行时才计时,定时到达时发送给进程一个SIGVTALRM信号
  • profile:间隔定时器进程执行在用户态或核心态时都计时,当定时到达时发送给进程一个SIGROF信号

Linux系统允许进程同时启动多个定时器,定时器工作所需时间值及有关信息保存在进程的task-struct中

中断优先级和多重中断

对同时发生的中断

  • 硬件方法:根据排定的优先级顺序做一个硬件链式排队器,当产生高一级中断事件时,屏蔽比它优先级低的所有中断源
  • 软件方法:编写一个查询程序,依据优先级顺序从高到低进行查询,一旦发现有中断请求,便转入相应中断事件处理程序入口

中断屏蔽

CPU可以通过指令设置可编程中断控制器的屏蔽码
中断屏蔽是指禁止CPU响应中断或禁止中断产生

  • 禁止CPU响应中断指硬件产生中断请求后,CPU暂时不予响应的状态,等待直到中断开放后,被屏蔽的中断才能被响应并获得处理。常常用在处理某个中断时,防止同级或高级中断干扰,或内核处理临界区时,必须连续执行防止被意外事件打断
  • 禁止中断产生指可引起中断的事件发生时,硬件不允许提出中断请求,也不通知处理器,故不可能导致中断。由于中断被禁止而不可能导致中断,通常设备中断、时钟中断等可以被暂时禁止

中断屏蔽的作用

  • 延迟或禁止某些中断的响应
    系统程序执行过程中,不希望产生干扰事件,以免共享数据结构受到破坏
    程序运行过程中产生某些事件认为是正常的,不必加以处理
  • 协调中断响应与中断处理的关系
    确保高优先级中断可以打断低优先级中断,反之却不能
  • 防止同级中断相互干扰
    在处理某优先级中断事件时,必须屏蔽该级中断,以免造成混乱

中断处理的局限性

负责对硬件做出迅速响应,并完成时间要求很严格的操作

  • 异步方式执行,可能会打断其他重要代码的执行
  • 中断处理程序执行过程中
    最好情形下,同级中断被屏蔽
    最坏情形下,当前处理器上所有其他中断都会被屏蔽
  • 中断处理程序不在进程上下文中运行,不能被阻塞

中断处理流程

上半部:中断处理程序

  • 简单快速,执行时禁止部分或全部中断

下半部:

  • 执行与中断处理密切相关但中断处理程序本身不执行的工作
  • 执行期间可以响应中断

上半部分与下班部分的划分

没有严格的划分规则

  • 如果任务对时间非常敏感,放在中断处理程序中执行
  • 如果任务与硬件相关,放在中断处理程序中执行
  • 如果任务需确保不被其他中断(同级中断)打断,放在中断处理程序中执行
  • 其他任务,考虑放置在下半不执行

下半部实现机制的演化过程

软中断
tasklet
工作队列

tasklet实现在软中断之上;tasklet和软中断也称为可延迟函数

可延迟函数的基本操作

  • 初始化
    定义一个新的可延迟函数,该操作通常在内核初始化或加载模块时进行
  • 激活
    标记一个可延迟函数为“挂起”(在可延迟函数的下一轮调度中执行)
    激活可在任何时候进行(即使正在处理中断)
  • 屏蔽
    有选择地屏蔽一个函数,使其即使被内核激活也不执行
  • 执行
    执行一个挂起的、可延迟函数及同类型的其他所有挂起的可延迟函数
    在特定的时间上执行

软中断概念

一组静态定义的下半部接口

  • 有32个,必须在编译阶段静态注册
  • 可以在所有处理器上同时执行(即使两个类型相同的软中断)
  • 一个软中断不会抢占另一个软中断
  • 软中断处理过程中允许响应中断,但自己不能休眠
  • 在一个处理程序运行的时候,当前处理器上的软中断被禁止

软中断预留给系统中对时间要求最严格以及最重要的下半部使用
适用于执行频率很高且连续性要求很高的情况

tasklet概念

基于软中断实现、灵活性强、动态创建

  • 类型相同的tasklet不能同时执行
  • 两种不同类型的tasklet可以在不同处理器上同时执行
  • tasklet由HI_SOFTIRQ及TASKLET_SOFTIRQ两类软中断代表组成,前者的优先级高于后者

tasklet与软中断的权衡

  • 通常应该使用tasklet
  • 软中断适用于执行频率很高且连续性要求很高的情况

tasklet调度:激活相应软中断的挂起状态

基于软中断实现、灵活性强、动态创建

工作队列

将工作推后,交由一个内核线程去执行

  • 下半部分在进程上下文执行,通过工作队列执行的代码可以占尽进程上下文的所有优势(支持使用大容量内存, 支持获取信号量, 支持执行阻塞式I/O操作)
  • 工作队列可以用内核线程替换,但一般不建议单独建立对应的内核线程

工作队列vs.软中断/tasklet

  • 工作队列支持睡眠,软中断/tasklet不支持
  • 若需要使用一个可以重新调度的实体来执行下半部分处理,则应该使用工作队列

进程及其实现

引入进程原因

  • 刻画程序的并发性
  • 解决资源的共享性

可再用程序与可再入程序

“可再用” 程序

  • 在被调用过程中可以有自身修改,调用程序退出前不允许其他程序来调用

“可再入”

  • 能够被多个程序同时调用的程序
  • 是纯代码,在执行过程中不被修改
  • 调用它的各应用程序提供工作区

进程定义和属性

定义:

  • 进程是可并发执行的程序在某个数据集合上的一次计算活动,也是操作系统进行资源分配和保护的基本单位

进程性质

  • 原理角度:是支持程序执行的一种系统机制,它对处理器上运行程序的活动规律进行抽象
  • 实现角度:是一种数据结构,用来准确地刻画运行程序的状态和系统动态变化状况

分析

  • 进程是一个既能用来共享资源,又能描述程序并发执行过程的系统基本单位

引入进程的代价:进程占用的空间、调度进程的时间代价

属性:

  • 动态性
    一次执行过程、有生命周期、创建/调度/等待
  • 共享性
    同一程序同时运行于不同数据集合上时,构成不同进程
    进程和程序不是一一对应的
  • 独立性
    独立实体,有自己的虚存空间、程序计数器和内部状态
  • 制约性
    共享资源或协同工作,产生相互制约关系,必须对进程的执行次序,或相对执行速度加以协调
  • 并发性
    多个进程的执行在时间上可以重叠
    在多处理器环境中可并行执行

进程状态和转换

OS Review2 处理器管理_第1张图片
OS Review2 处理器管理_第2张图片

进程挂起

挂起状态引入原因

  • 为了让某些进程暂时不参与低级调度,释放它占有的资源,以平滑系统负荷

进程挂起的原因多种多样,如

  • 内存资源已经不能满足进程运行的要求,此时必须把某些进程挂起(suspend),对换到磁盘对换区中
  • 可能系统出现故障,需要暂时挂起一些进程,以便故障消除后,再解除挂起并恢复进程运行
  • 用户调试程序过程中,可以请求挂起他的进程,以便进行某种检查和修改

OS Review2 处理器管理_第3张图片

进程挂起的特征

进程不能立即被执行

  • 挂起进程可能会等待事件,但所等待事件是独立于挂起条件的,事件结束并不能导致进程具备执行条件
  • 进程进入挂起状态是由于操作系统、父进程或进程本身阻止它的运行
  • 结束进程挂起状态的命令只能通过操作系统或父进程发出

进程描述和组成

进程映象定义

  • 某时刻进程的内容及其状态集合

进程映象组成

  • 进程控制块
    每个进程捆绑一个,用来存储进程的标志信息、现场信息和控制信息
  • 进程程序块
    被进程执行的程序,规定进程一次运行所应完成的功能
  • 进程核心栈
    每个进程捆绑一个,进程在内核态工作时使用,用来保存中断/异常现场,保存函数调用的参数、局部变量和返回地址等
  • 进程数据块
    进程的私有地址空间,存放各种私有数据,用户栈也在数据块中开辟,用于在函数调用时存放栈帧、局部变量和返回地址等参数

进程上下文切换与处理器状态转换

进程上下文:

  • 进程上下文是进程物理实体和支持进程运行的环境

进程上下文组成:

  • 用户级上下文
    由程序块(可执行的机器指令序列)、数据块(进程可访问的信息)、共享内存区(进程通信使用的内存区)、用户栈(存放函数调用过程中的信息)组成,占用进程的虚存空间
  • 系统级上下文
    由进程控制块(进程的状态)、内存管理信息(进程页表或段表)、核心栈(进程内核态运行时的工作区)等操作系统管理进程所需要的信息组成
  • 寄存器上下文
    由处理器状态寄存器(进程当前状态)、指令计数器(下一条该执行的指令地址)、栈指针(指向用户栈或核心栈当前地址)、通用寄存器等组成
    当进程不处于运行态时,处理器状态信息保存在寄存器上下文中

进程控制块

也称为进程描述符(process descriptor)

  • 进程存在的唯一标识
  • 操作系统用来记录和刻画进程状态及环境信息的数据结构,是进程动态特征的汇集
  • 操作系统掌握进程的唯一资料结构和管理进程的主要依据

进程控制块包含三类信息

  • 标识信息
    包括用户外部标识符(用户/用户组标识ID)和系统内部标识号(进程/进程组标识ID )
  • 现场信息
  • 控制信息
    用于管理和调度进程,包括进程调度相关信息、进程组成信息、进程族系信息、进程间通信信息、进程段/页表、进程映像在外存中的地址、CPU的占用和使用信息、进程特权信息 、资源清单

进程控制和管理

进程队列:处于同一状态的所有PCB链接在一起的数据结构

队列排队规则

  • 可按先来先到、优先数或其它原则排队

通用队列组织方式

  • 链接方式
    单向链接的每个PCB的链接指针向下一个进程PCB的地址或在PCB表中的编号,编号为0表示队尾
    双向链接的每个PCB的前向链接指针指向上一个进程的PCB的地址或在PCB表中的编号,编号为0表示排在队首;向随其后的下一个进程的PCB的地址或在PCB表中的编号,编号为0表示排在队尾
  • 索引方式

进程上下文切换:

  • 进程切换是让处于运行态的进程中断运行,让出处理器,这时要做一次进程上下文切换
  • 程切换发生位置:在内核态而非用户态发生

进程上下文切换步骤

  • 保存被中断进程的处理器现场信息
  • 修改被中断进程的进程控制块有关信息,如进程状态等
  • 把被中断进程的PSW加入有关队列
  • 选择下一个占有处理器运行的进程
  • 修改被选中进程的PSW的有关信息
  • 根据被选中进程设置操作系统用到的地址转换和存储保护信息
  • 根据被选中进程恢复处理器现场

进程调度与切换时机

  • 内核发现满足调度条件,便可请求重新调度
  • 内核中不能立即进行调度和切换的情况
    内核正在处理中断过程中
    进程运行在内核临界区中
    内核处在需要屏蔽中断的原子操作过程中
    解决方案:采用置请求调度标志,延迟到敏感性操作完成后才进行

处理器的状态切换(用户态-内核态)不一定引起进程上下文切换

中断上下文 VS. 进程上下文

  • 中断上下文不存在进程背景,不可能被阻塞,也不能调用引起阻塞的函数
  • 中断上下文之间切换或执行代码的过程,绝不可能插入调度器调度例程的调用

Linux进程与任务

  • Linux把内核空间中运行的程序称为任务,而在用户空间中运行的程序称为进程
  • 系统中存在两种进程(任务)
    系统进程(任务)和用户进程(任务),实质上是指一个进程(任务)的两个侧面
    两个进程(任务)所执行的程序不同,映射到不同物理地址空间、使用不同的堆栈

OS Review2 处理器管理_第4张图片

进程的控制与管理

由操作系统中的原语实现:

  • 在管态下执行
  • 执行过程中不允许被中断
  • 执行是顺序的而不可能是并发的

进程的创建

当一个进程创建另一个进程时,生成进程称为父进程,被生成进程称为子进程,父进程可以创建多个子进程,从而形成树状族系关系

进程创建过程:

  • 在进程列表中增加一项,从PCB池中申请一个空闲PCB,为新进程分配惟一的进程标识符
  • 为新进程的进程映像分配地址空间,以便容纳进程实体:进程管理程序确定加载到进程地址空间中的程序
  • 为新进程分配除主存空间外的其他各种所需资源
  • 初始化PCB,如进程标识符、处理器初始状态、进程优先级等
  • 把新进程状态置为就绪态,并移入就绪进程队列
  • 通知操作系统的某些模块,如记账程序、性能监控程序

linux创建进程/线程

fork( ):父子进程是独立的进程
clone( ) :父子进程允许共享资源
vfork( ):子进程租用父进程地址空间

进程撤销

进程完成特定工作或出现严重错误后,必须被撤销,进程撤销可分为:正常撤销和非正常撤销

进程撤销过程:

  • 根据撤销进程标识号,从相应队列中找到并移出它
  • 将该进程拥有的资源归还给父进程或操作系统
  • 若该进程拥有子进程,先撤销所有子进程,以防它们脱离控制
  • 回收PCB,并归还到PCB池

进程的阻塞和唤醒

  • 进程阻塞指使进程让出处理器,转而等待一个事件(如等待资源、等待I/O操作完成)
  • 阻塞是进程的自主行为,是一个同步事件
  • 等待事件完成时会产生一个中断,激活操作系统,在系统的控制下将被阻塞进程唤醒
  • 进程的阻塞和唤醒显然是由进程切换来完成

进程阻塞步骤:

  • 停止进程执行,保存现场信息到PCB
  • 修改进程PCB有关内容(如进程状态由运行态改为等待态等),并把修改状态后的进程移入相应事件的等待队列中
  • 转入进程调度程序去调度其他进程运行

进程唤醒步骤:

  • 从相应的等待队列中移出进程
  • 修改进程PCB的有关信息(如进程状态改为就绪态),并移入就绪队列
  • 若被唤醒进程比当前运行进程优先级高,重新设置调度标志

线程及其实现

引入多线程的动机

  • 引入进程的目的是为了使多个程序并发执行,改善资源使用率和提高系统效率
  • 再引入线程,则是为了减少程序并发执行时所付出的时空开销,使得并发粒度更细、并发性更好

解决思路:把进程的两项功能:“独立分配资源”与“被调度分派执行”分离开来

  • 进程作为系统资源分配和保护的独立单位,不需要频繁地切换
  • 线程作为系统调度和分派的基本单位,能轻装运行,会被频繁地调度和切换

线程的优点

  • 快速线程切换
    同一进程中的多线程切换只需改变堆栈和寄存器,地址空间不变
  • 通信易于实现
    自动共享进程的内存和文件,线程可自由访问全局数据,线程通信相对简单不必经过内核
  • 减少管理开销
    线程创建和撤销工作比进程少很多,并且无需再分配存储空间和各种资源
  • 并发程度提高
    多线程适宜并行工作,能充分发挥处理器与设备的并行工作能力,使多核和多处理器系统的效能发挥得更好

多线程环境中的进程和线程

进程是操作系统中除处理器外进行的资源分配和保护的基本单位

  • 它有独立的虚拟地址空间,容纳进程映像(如与进程关联的程序与数据),并以进程为单位对各种资源实施保护,如受保护地访问处理器、文件、外部设备等

线程是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位

  • 线程是进程的组成部分,每个进程内允许包含多个并发执行的实体(控制流),这就是多线程

进程vs.线程

  • 线程又称轻量进程
  • 线程运行在进程的上下文中,并使用进程的资源和环境
  • 系统调度的基本单位是线程而不是进程,每当创建一个进程时,至少要同时为该进程创建一个线程

OS Review2 处理器管理_第5张图片

线程的实现

线程的组成

  • 线程唯一标识符及线程状态信息(运行态、就绪态、阻塞态和终止态)
  • 线程是一条执行路径,有独立的程序计数器,未运行时保护线程上下文
  • 线程有执行栈和存放局部变量的私用存储空间
  • 可访问所属进程的内存和资源,并与该进程中的其他线程共享这些资源

线程的状态

线程状态:运行、就绪、等待和终止
由于线程不是资源拥有单位,挂起状态对线程是没有意义

线程组织

  • 调度员/工作者模式
    进程中的一个线程担任调度员,接收和处理工作请求,其他线程是工作者线程,由调度员线程分配任务并唤醒工作者线程

  • 组模式
    各个线程都可以取得并处理工作请求,有时每个线程被设计成专门执行特定任务,并建立相应任务队列

  • 流水线模式
    线程排成某个次序,第一个线程所产生的数据传送给下一个线程进行处理,依次类推,数据按照排定次序由线程依次传递以完成被请求的任务

  • 多线程技术的应用

线程的实现

  • 内核级线程KLT(如OS/2)
    内核级线程指线程管理工作由内核完成,并提供线程API来使用线程

  • 用户级线程ULT(如Java ,Informix)
    用户级线程指线程的管理工作由应用程序来做,在用户空间内实现,内核不知道线程的存在
    线程库是一个ULT管理的例行程序包,主要功能有:线程创建、调度、管理等

  • 混合式线程(如Solaris)
    实现分为两个层次:用户层和核心层
    用户层线程在用户线程库中实现,核心层线程在内核中实现
    在混合式线程系统中,内核必须支持内核级多线程的建立、调度和管理,同时也允许应用程序建立、调度和管理用户级线程

内核级线程特点

优点

  • 在多处理器上核能够同时调度同一进程中的多线程并行执行
  • 若进程中的一个线程被阻塞 ,内核能够调度同一进程的其他线程占有处理器运行,也可以运行其他进程中的线程
  • 由于内核级线程只有很小的数据结构和堆栈,切换速度快,内核自身也可用多线程技术实现,从而,提高系统的执行效率

缺点

  • 线程在用户态运行,而线程的调度和管理在内核实现,在同一进程中,控制权从一个线程传送到另一个线程时需要用户态-内核态-用户态模式切换,系统开销较大

用户级线程特点

优点

  • 线程切换无须使用内核特权方式,所有线程管理的数据结构均在用户空间中,可以节省模式切换开销和内核的宝贵资源
  • 允许进程按照应用的特定需要选择调度算法,且线程库的线程调度算法与操作系统的低级调度算法无关
  • 能够运行在任何操作系统上,内核无须做任何改变

缺点

  • 由于大多数系统调用是阻塞型的,因此,一个用户级线程的阻塞将引起整个进程阻塞
  • 用户级线程不能利用多重处理的优点,进程由内核分配到CPU上,仅有一个用户级线程可以执行,因此不可能得益于多线程的并发执行

混合式线程特点

  • 一个应用程序中的多个用户级线程能分配和对应于一个或多个内核级线程
  • 内核级线程可同时在多处理器上并行执行,且在阻塞一个用户级线程时,内核可以调度另一个线程执行
  • 在宏观上和微观上都具有很好的并行性

线程调度

操作系统调度程序需要根据是用户级线程还是内核级线程来决定对进程和线程的调度方法

  • 用户级线程的调度
    由于内核并不知道有线程存在,所以,操作系统调度程序还是以进程为单位进行调度
  • 内核级线程的调度
    操作系统调度程序会选择一个优先级高的线程运行,不用考虑该线程属于哪个进程

Linux进程

Linux进程创建特点

现代UNIX内核:引入三种机制优化进程创建效率

  • 写时复制技术(Copy-On-Writing)
  • 轻量级进程
    允许父子进程共享页表、打开文件列表、信号处理等数据结构
    但每个进程应该有自己的程序计数器、寄存器集合、核心栈和用户栈
  • vfork()
    新进程可共享父进程的内存地址空间

OS Review2 处理器管理_第6张图片

fork() 函数

  • fork() 执行后的父子进程执行顺序和具体环境有关,没有一个确定的顺序。

参考另一位博主的阐述:

  • fork()函数调用之后子进程从fork()语句之后开始执行,其原因是子进程复制了程序计数器
  • 在刚刚fork之后父子进程之间的数据段(全局变量),栈段(局部变量),堆段(动态内存),代码段,程序计数器等都是相同的(在当前的linux版本中遵从的是读时共享写时复制的原则)
  • 父子之间不同的是进程ID,fork函数的返回值
  • 共享的是文件描述符以及mmap建立的映射区 ———————————————— 版权声明:本文为CSDN博主「JoshuaCL」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_27357649/article/details/90939370

vfork()函数

vfork()创建的子进程与父进程共享地址空间

  • 子进程作为父进程的一个单独线程在其地址空间运行
  • 子进程从父进程继承控制终端、信号标志位、可访问的主存区、环境变量和其他资源分配
  • 子进程对虚拟空间任何数据的修改都可为父进程所见
  • 父进程将被阻塞,直到子进程调用execve()或exit()

与fork()的关系

  • 功能相同,但vfork()但不拷贝父进程的页表项
  • 子进程只执行exec()时,vfork()为首选

参考另一位博主关于fork()与vfork()的详细解释:
可以看出使用vfork时,系统调用会等待子进程开始执行后返回,其实这样操作的原因也是因为子进程没有自己的页表项,如果不做等待的操作,会导致主进程和子进程使用同样页表,两个进程用样的页表,想想后果吧。
所以可以看出vfork和fork本质上的区别是:fork的子进程会拷贝主进程的页表项,而vfork的子进程共享主进程的页表项。

    因为这样的区别,所以使用vfork时主进程会等待子进程执行exec或exit操作后才会开始执行;如果vfork的子进程中不包含exec或者exit操作,而是直接退出,则会有导致主进程的操作异常,因为主进程的页表项在子进程退出的时候已经销毁,相当于主进程自己没了页表项。

    那么vfork的好处是什么呢?避免一次主进程页表项的拷贝,因为子进程一般都会调用exec执行自己的程序代码,而在exec过程中会创建自己的页表项,根本不需要复制主进程的页表项。

    那么vfork在现代Linux中是否真能体现它的优点呢?其实不尽然。

    在拷贝页表项时,调用了函数dup_mm,其中会使用到COW(写时复制)技术(dup_mm-->copy_page_range),所谓的内存拷贝其实只是对内存的一个标记,只有在需要对该区域进行标记而已,并不会真正的拷贝。

———————————————— 版权声明:本文为CSDN博主「江明大吴」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wu330/article/details/49127835

另一篇博主关于fork、vfork、clone的介绍blog

linux线程的创建

OS Review2 处理器管理_第7张图片

linux内核线程

也称为守护进程,独立运行在内核空间的标准进程,支持内核在后台执行一些操作

  • 刷新磁盘高速缓存
  • 交换出不用的页框
  • 维护网络链接等待

与普通进程的区别:

  • 只运行在内核态,内核线程没有独立的地址空间(mm指针被设置为NULL)
  • 每个内核线程执行一个单独的内核函数
  • 只使用大于PAGE_OFFSET的线性地址空间

mm

  • 指向虚存地址空间的用户空间部分
  • 内核线程不能访问用户空间,mm为NULL

active_mm:主要用于优化

  • 由于内核线程之前可能是任何用户层进程在执行,内核线程不能修改其内容,故将mm设置为NULL
  • 如果切换出的是用户进程,内核将原来进程mm存放在新内核线程的active_mm中
  • 如果内核线程之后运行的进程与之前是同一个,内核并不需要修改用户空间地址表,TLB中的信息仍然有效
  • 如果内核线程之后运行的进程与之前不是同一个,才需要切换,并清除对应的TLB数据

处理器调度

处理机调度层次

高级调度,又称作业调度、长程调度

  • 从输入系统的一批作业中按照预定的调度策略挑选若干作业进入内存,为其分配所需资源,并创建对应作业的用户进程
  • 将控制多道程序的道数,被选择进入内存的作业越多,每个作业所获得的CPU时间就越少,为了向用户提供满意的服务,有时需要限制内存中同时运行的进程数

中级调度,又称平衡调度、中程调度

根据内存资源情况决定内存中所能容纳的进程数目,并完成外存和内存中的进程对换工作

低级调度,又称进程调度/线程调度、短程调度

根据某种原则决定就绪队列中的哪个进程/线程获得处理器,并将处理器出让给它使用

选择调度算法的原则

  • 资源利用率
    CPU利用率=CPU有效工作时间/CPU总的运行时间
    CPU总的运行时间=CPU有效工作时间+CPU空闲等待时间
    在一定的I/O操作等待时间的比率下,运行程序的道数越多,CPU空闲时间所占的百分比越低
  • 吞吐率
    单位时间内处理的作业数
  • 公平性
    确保每个用户每个进程获得合理的CPU份额或其他资源份额,不会出现饿死情况
  • 响应时间:这是分时系统和实时系统衡量调度性能的一个重要指标
    交互式进程从提交一个请求(命令)到接收到响应之间的时间间隔称响应时间
  • 周转时间:这是批处理系统衡量调度性能的一个重要指标
    批处理用户从作业提交给系统开始,到作业完成为止的时间间隔称作业周转时间
  • 带权周转时间
    作业的周转时间T与系统为其提供服务的服务时间之比

作业管理与调度

作业和进程的关系

  • 作业(JOB) 是用户提交给操作系统计算的一个独立任务,每个作业必须经过若干相对独立且相互关联的顺序加工步骤才能得到结果
  • 作业是任务实体,进程是完成任务的执行实体

低级调度功能和类型

低级调度的基本类型

剥夺式(preemptive) ,又称抢先式

  • 高优先级进程/线程可剥夺低优先级进程/线程
  • 当运行进程/线程时间片用完后被剥夺

非剥夺式(nonpreemptive),又称非抢先式

  • 一旦某个进程/线程开始运行后便不再让出处理器,除非
  • 进程/线程运行结束
  • 主动放弃处理器
  • 因发生某个事件而不能继续执行

剥夺式vs.非剥夺式

  • 剥夺式策略比非剥夺式策略开销要大,主要是调度程序自身开销,及内存和磁盘对换程序及数据的开销
  • 剥夺式策略可以避免进程/线程长时间地独占处理器,对于实时系统和分时系统有利,能为用户提供高性能服务

作业调度和低级调度算法

1、先来先服务算法(First Come First Severed,FCFS)

  • 平均作业周转时间与作业提交的顺序有关
  • 不利于短作业而优待了长作业
  • 不利于I/O繁忙型作业而有利于CPU繁忙型作业

2、最短作业优先算法 (Shortest Job First,SJF)

  • 算法易于实现,效率不高,主要弱点是忽视了作业等待时间,会出现饥饿现象
  • SJF的平均作业周转时间比FCFS要小,调度性能比FCFS好
  • 实现SJF调度算法需要知道作业所需运行时间,否则调度就没有依据,要精确知道一个作业的运行时间是办不到的

3、最短剩余时间优先算法(Shortest Remaining Time First,SRTF)

把SJF算法改为抢占式的:

  • 如果新作业需要的CPU时间比当前正在执行的作业剩余下来还需的CPU时间短,SRTF强行赶走当前正在执行作业

4、最高响应比优先算法(Highest Response Ratio First,HRRF)

FCFS与SJF是片面的调度算法

  • FCFS只考虑作业等候时间而忽视了作业的计算时问
  • SJF只考虑用户估计的作业计算时间而忽视了作业等待时间

HRRF是介乎这两者之间的折衷的非剥夺式算法

  • 选择响应比最高者投入运行
    既考虑作业等待时间,又考虑作业的运行时间
    既照顾短作业又不使长作业的等待时间过长
  • 响应比定义
    响应比 =1+已等待时间/估计运行时间
    短作业容易得到较高响应比
    长作业等待时间足够长后,也将获得足够高的响应比
    饥饿现象不会发生
  • HRRF 算法缺点
    计算响应比导致一定时间开销,其性能比 SJF 算法略差

5、优先级调度算法

静态优先数法

  • 使用外围设备频繁者优先数大,这样有利于提高效率
  • 重要算题程序的进程优先数大,这样有利于用户
  • 进入计算机时间长的进程优先数大,这样有利于缩短作业完成的时间
  • 交互式用户的进程优先数大,这样有利于终端用户的响应时间等等

动态优先数法

  • 根据进程占有CPU时间多少来决定:
    当进程占有CPU时间愈长,被阻塞后再次获得调度的优先级就越低
  • 根据进程等待CPU时间多少来决定:
    当进程在就绪队列中等待时间愈长,被阻塞之后再次获得调度的优先级就越高

6、轮转法调度(Round-Robin,RR)

时间片调度

  • 调度程序每次把CPU分配给就绪队列首进程使用一个时间片,就绪队列中的每个进程轮流地运行一个时间片
  • 当这个时间片结束时,强迫一个进程让出处理器,让它排列到就绪队列的尾部,等候下一轮调度

轮转策略可防止那些很少使用外围设备的进程过长的占用处理器而使得要使用外围设备的那些进程没有机会去启动外围设备

轮转策略与间隔时钟 :时间片的设定

7、多级反馈队列调度(Multi-Level Feedback Queue,MLFQ)

又称反馈循环队列或多队列策略

  • 将就绪进程分为两级或多级,系统相应建立两个或多个就绪进程队列,较高优先级的队列一般分配给较短时间片
  • 处理器调度先从高级就绪进程队列中选取可占有处理器的进程,只有在选不到时,才从较低级的就绪进程队列中选取

Linux调度算法

调度策略设计的技术难点

  • 如何动态管理和维护就绪进程
  • 进程调度相关数据结构设计
  • 如何设定进程优先级
    进程类型:实时进程 vs.交互式进程 vs. 普通进程
    进程动态/动态优先级的定义
    进程动态优先级调整策略及调整时机
  • 如何设置/调整进程CPU时间片
    初始值设置原则
    时间片修改/调整位置、时机及策略(进程创建/运行/退出)
  • 进程调度/切换依据
    如何选择侯选进程
    与静态/动态优先级、进程类型、时间片等的关系
  • 多处理器系统SMP
    CPU选择策略
    负载均衡与迁移机制

Linux进程调度基本机制

调度方法

  • 基于分时技术的抢占式调度
    CPU时间被划分成“时间片”,为每个可运行进程分配一个时间片
    分时依赖于时钟中断,对进程透明

调度策略

  • 进程分类
    普通进程
    实时进程
  • 优先级
    静态优先级
    动态优先级

Linux2.4

  • 系统中调度算法属于O(n),开销线性增长(依赖goodness()计算相关进程权重进行分配)
  • 当大多数就绪进程的时间片都用完,且未重新分配时间片时
    SMP系统中将可能有部分处理器处于空闲状态
    一个全局就绪进程队列,对多处理器的伸缩性支持不好
    时间片的重算循环制约多处理器的效率
  • 空闲处理器执行时间片尚未用尽,而处于等待状态的进程时,会导致进程开始在处理器之间“跳跃”
    处理器的亲和性不好
    实时进程或者占用内存大的进程在处理器之间跳跃会严重影响系统的性能
  • 交互式进程支持不够
  • 不支持内核抢占

OS Review2 处理器管理_第8张图片
有静态优先级、动态优先级、实时优先级

Linux2.6

  • 提供完全O(1)调度算法
    不管系统有多少进程,调度算法都必须在常数时间内完成调度
  • 对SMP有良好可伸缩性
    每个处理器应有独立的可执行进程队列和锁机制
  • 提高SMP处理器的亲和性
    出现负载不均衡时,应具备在处理器间迁移进程的能力
    OS Review2 处理器管理_第9张图片
  • 基于每个CPU分配时间片,取消全局同步和重算循环
  • 每个处理器有两个数组:活动就绪进程队列和不活跃就绪进程队列
    进程消耗完其“时间片”后,进入不活跃就绪进程数组中相应队列的队尾
    当所有进程都“耗尽”其“时间片”后,交换活跃与不活跃就绪进程队列数组,不需要任何其他的开销
  • 每个数组中有140个就绪进程队列(runqueue),每个队列对应于140个优先级的一个
    通过位图标记队列状态
    调度时,通过find_first_bit()找到第一个非空的队列,并取队首进程
    不管队列中有多少就绪进程,挑选就绪程的速度恒定,因此称为0(1)算法

Linux 2.6负载均衡的“拉”操作基本思想

  • 当某个 CPU负载过轻、而另一 CPU负载较重时,系统会从重载 CPU上“拉”进程过来
  • “拉”的负载平衡操作实现在 load_balance() 函数中,有两种调用方式
  • “忙平衡”:当前 CPU不空闲
  • “空闲平衡”:当前 CPU空闲
  • “拉”进程的具体动作在pull_task()函数中实现

你可能感兴趣的:(操作系统)