【操作系统】进程与线程

2.1进程与线程

进程(更好地使多道程序并发执行,提高资源利用率和系统吞吐量)

  1. 为了更好地描述和控制程序地并发执行,实现OS的最基本的两个特性——并发性和共享性
  2. 进程实体/进程映像
    • 程序段
    • 相关数据段
    • PCB(进程控制块):进程存在的唯一标志
      • 创建进程:创建PCB
      • 撤销进程:撤销PCB
  3. 是系统进行资源分配和调度的一个独立单位
  4. 进程的特征:动态性、并发性、独立性、异步性
进程的状态与转换
  • 创建态

    • 申请PCB、分配必要资源、填写信息
      • 事件:用户登陆、作业调度、提供服务、应用请求
      • 执行:系统(如用户请求服务时)、进程
  • 就绪态

    • 获得了除处理机外的一切资源
  • 运行态

    • 进程在处理机上运行
      • 时间片用完后,让出处理机–>就绪态
      • 进程请求除处理机外的其他资源
    • 单处理机下同时最多一个
  • 阻塞态/等待态

    • 进程正在等待某一事件或等待其他资源的获得而暂停运行
  • 结束态

    • 置为结束态,资源释放

在这里插入图片描述

  1. 进程的组织方式
  • 链接方式
    • 按照进程状态将PCB分为多个队列
    • 操作系统持有指向各个队列的指针
  • 索引方式
    • 根据进程状态的不同,建立几张索引表
    • 操作系统持有指向各个索引表的指针
进程的组织
  • 进程控制块PCB的内容
    • 进程描述信息:进程标识符PID,用户标识符UID
    • 进程控制和管理信息:当前状态,优先级,代码入口,外存地址,时间
    • 资源分配清单:代码段、数据段、堆栈段的指针,文件描述符
    • 处理机相关信息:通用、地址、控制、标志寄存器的值,状态字
  • 程序段:内容可以被多个进程共享
  • 数据段:原始数据或中间结果
进程控制(用原语控制实现进程状态转换)
  • 进程的创建(创建原语)
    • 申请空白PCB,为进程分配资源,初始化PCB,将新进程插入就绪队列
  • 进程的终止(终止原语)
    • 根据被终止进程的标识符,找出该进程的PCB
      • 该进程处于执行状态:立即终止该进程,把处理机资源分配给其他进程
      • 该进程有子孙进程终止其所有子孙进程
      • 该进程有父进程:将该进程的所有资源归还给父进程或操作系统
    • 将该PCB从所在链表/队列中删除
  • 进程的堵塞和唤醒
    • Block阻塞原语(运行态–>阻塞态)
      • 引起进程阻塞的事件
        • 需要等待系统分配某种资源
        • 需要等待相互合作的其他进程完成工作
      • 执行过程
        • 找到将要被阻塞进程的标志号对应的PCB
        • (运行态)保护现场,将其转为阻塞态,停止运行
        • 把该进程插入相应事件的等待队列,把处理机资源调度给其他就绪进程
    • Wakeup唤醒原语(阻塞态–>就绪态)
      • 引起进程唤醒的事件
        • 阻塞进程期待的事件出现时
      • 执行过程
        • 等待队列中找到相应进程的PCB
        • 将进程从等待队列中移出,置为就绪态
        • 把该PCB插入就绪队列,等待调度程序调度
    • 阻塞(Block)原语和唤醒(Wakeup)原语必须成对使用
进程的通信
共享存储
  • 通信进程之间存在一块可以被直接访问的共享空间
  • 低级方式:基于数据结构的共享——速度慢
  • 高级方式:基于存储区的共享
  • 操作系统仅提供:存储空间和同步互斥工具,如信号量(P、V)
消息传递
  • 进程间的数据交换以格式化的消息为单位
  • 通过发送消息接收消息两个原语进行数据交换
  • 直接通信方式
    • 发送进程——接收进程(直接)
      • 挂在接收进程的消息缓冲队列上,接收进程从消息缓冲队列中取得消息
  • 间接通信方式
    • 发送进程——(中间实体/信箱)——接受进程
管道通信
  • 相当于一个固定大小缓冲区,一般一页
  • 半双工通信:不能同时读和写
    • 写满、读空后该调用会被阻塞
    • 写进程把缓冲区写满,才让读进程读,读进程最多只能有一个
    • 缓冲区还有数据时,写进程不会往缓冲区写数据
    • 其数据一旦被读取,该数据就会被抛弃
  • 实现全双工需要两个管道
  • 可有多个读写进程

线程(减小程序在并发执行时的时空开销,提高操作系统的并发性能)

  1. 线程的基本概念
    • 调度的基本单位
    • 是“轻量级进程”,是最基本的CPU执行单元,是执行流的最小单元
    • 也有就绪、阻塞和运行三种基本状态
    • 引入线程后:进程只作为除CPU外的系统资源的分配单位
    • 线程仅拥有线程ID、寄存器集合和堆栈
      • 可以访问其隶属进程所有资源(如虚拟地址空间),但线程间相互不行
  2. 线程与进程的比较
    • 调度
    • 并发性
    • 拥有资源
    • 独立性
    • 系统开销:系统为创建/撤销PCB付出的开销**>>**创建/撤销线程时的开销
    • 支持多处理机系统
  3. 线程的属性
    • 每个线程都有一个线程ID和TCB
    • 线程时处理机的独立调度单位
    • 同一进程的各个线程共享该进程所拥有的资源
    • 切换同进程内的线程,系统开销很小
    • 不拥有系统资源(仅有一点必不可少、能保证独立运行的资源)
    • 线程的状态和转换:执行状态、就绪状态、阻塞状态
线程的组织与控制
  • 线程控制块(TCB):记录控制和管理线程的信息
    • 线程标志符TID
    • 寄存器:PC、PSW、通用寄存器
    • 堆栈指针
    • 线程运行状态
    • 优先级
  • 线程的创建
  • 线程的终止

线程的实现方式

进程库支持的线程:用户级(ULT)
  • 所有工作都由应用程序通过线程库在用户空间实现
  • 优点
    • 切换不需要转换到内存空间,节省开销
    • 实现与OS平台无关
  • 缺点
    • 线程被阻塞,等于进程被阻塞
    • 无法充分利用多处理器
  • 多对一
内核支持的线程:内核级(KLT)
  • 所有工作内核空间实现
  • 优点:适合多处理器,是==处理机分配的单位==
  • 缺点:线程切换需要转到内核态,开销大
  • 一对一:每个线程有线程控制块
组合方式
  • 多个用户级,与多个内核级对应
  • 集两者之所长
  • 多对多

2.2处理机调度

2.2.1调度的概念

处理机调度是对处理机进行分配,是多道程序操作系统的基础

调度的层次

调频次数:低级>中级>高级

高级调度(作业调度)
  • 外存–>内存(面向作业)
  • 无——创建态——就绪态
  • 作业调入时会建立PCB,调出时会才撤销PCB
  • 给作业分配内存、I/O设备等必要资源
  • 为进程活动做准备,使进程正常活动起来
中级调度(内存调度)
  • 外存–>内存(面向过程)
  • 内存不够时,将暂时不能运行的进程调至外存等待(挂起态)
  • 把外存上具备运行条件的就绪进程重新调入内存,并修改其状态为就绪态,挂在就绪队列上等待
  • 挂起态——就绪态
  • 目的:提高内存利用率和系统吞吐量
低级调度(进程调度/处理机调度)
  • 内存–>CPU
  • 将处理机分配给进程,是最基本的调度
  • 就绪态——运行态

2.2.2调度的目标

  • CPU利用率
    C P U 利用率 = C P U 有效工作时间 C P U 有效工作时间 + C P U 空闲等待时间 CPU利用率=\frac{CPU有效工作时间}{CPU有效工作时间+CPU空闲等待时间} CPU利用率=CPU有效工作时间+CPU空闲等待时间CPU有效工作时间

  • 系统吞吐量

  • 周转时间:从作业提交到作业完成的时间
    平均周转时间 = Σ ( 作业完成时间 − 作业提交时间 ) 作业数 平均周转时间=\frac{\Sigma(作业完成时间-作业提交时间)}{作业数} 平均周转时间=作业数Σ(作业完成时间作业提交时间)

    带权周转时间 = 作业周转时间 作业实际运行时间 带权周转时间=\frac{作业周转时间}{作业实际运行时间} 带权周转时间=作业实际运行时间作业周转时间

  • 等待时间

    • 进程出于等处理机的时间之和
  • 响应时间

    • 用户提交请求到系统首次产生响应所用时间

2.2.3调度的实现

调度程序(调度器)

调度的时机、切换与过程

  • 不能进行进程的调度与切换的情况
    • 在处理中断的过程中
    • 进程在操作系统内核临界区
    • 其他需要完全屏蔽中断的原子操作过程
  • 应该进行进程调度与切换的情况
    • 发生引起调度条件且当前进程无法继续运行下去时,可马上进行进程调度与切换
      • 非剥夺
    • 中断处理结束或自陷处理结束,若置上请求调度标志,则可马上进行进程调度与切换
      • 剥夺
  • 进程切换要求保存原进程当前断点的现场信息(推入当前进程的内核堆栈,并更新堆栈指针),恢复被调度进程的现场信息(在其内核栈中装入新进程的现场信息、更新空间指针、重设PC寄存器等)

进程调度方式

关中断状态下无法调度程序(要时钟中断来算时间片)

  • 非抢占调度方式(非剥夺方式)
    • 无法及时处理紧急任务
    • 仅当前进程阻塞/退出才触发调度
  • 抢占调度方式(剥夺方式)
    • 每k个时钟中断可能触发
    • 优先处理更紧急的进程
    • 通过时钟中断,让各进程按时间片轮转执行
  • 闲逛进程(idle)
    • 系统中无就绪进程运行,CPU永不空闲
    • 优先级最低,耗能也低
    • 不需要CPU以外的资源,不会被堵塞
    • 常用零地址指令,占一个完整指令周期(有检查中断)
  • 两种线程的调度
    • 用户级线程调度
    • 内核级线程调度
      • 内核级线程切换代价高(切换上下文)
      • 内核级线程并发度高

2.2.4经典的调度算法

先来先服务FCFS
  • 选择最先进入该队列的一个/几个作业
  • 既可用于作业调度,也可用于进程调度
  • 非抢占式
  • 不能作为分时系统和实时系统的主要调度策略
  • 对长作业有利,但对短作业不利
  • 有利于CPU繁忙型作业,而不利于I/O繁忙型作业
短作业优先SJF
  • 选择运行时间最短的作业,将其调入内存
  • 对短作业有利,对长作业不利
  • 会导致长作业长期不被调度,“饿死”
  • 默认:非抢占式,也有最短剩余时间
  • 在所有进程同时可运行情况下,平均等待时间、平均周转时间最短
优先级调度算法
  • 静态优先级(有饥饿)、动态优先级(考虑等待时间)
  • 一般
    • 系统进程优先级高于用户
    • 交互性(前台)高于非交互(后台)
    • I/O型进程高于计算型
  • 注:优先级与进程长短、需求资源多少无关
高响应比优先算法
  • 主要用于作业调度,在每次作业调度时,先计算后备作业队列中每个作业的响应比,选最高

  • 响应比 = 等待时间 + 要求服务时间 要求服务时间 ( ≥ 1 ) 响应比=\frac{等待时间 + 要求服务时间} {要求服务时间}(≥1) 响应比=要求服务时间等待时间+要求服务时间1

  • 综合FCFS和SJF,非抢占式无饥饿现象

时间片轮转算法
  • 公平、调度开销大
  • 抢占式
  • 适用于分时系统,适合交互式系统
  • 时间片过大:退化为先来先服务调度算法
  • 时间片过小:处理机在进程间过于频繁地切换,处理机开销增大,真正用于运行进程地时间减少
  • 时间片长短的决定因素
    • 系统的响应时间
    • 就绪队列中的进程数目
    • 系统的处理能力
多级队列调度算法
  • 设置多个就绪队列
    • 其优先级、时间片、调度算法可不同
多级反馈队列调度算法
  • 分多级队列,优先级渐低,时间片渐大
    • 级内FCFS
  • 时间片用完,放到下一级队列末尾
  • 低级队列空时,才执行高级队列
    • 抢占式:执行时,有高优先级的来了,立即切换
有饥饿
  • 短作业优先算法SJF
  • 优先级调度算法
  • 多级反馈队列调度算法

2.2.5上下文及其切换机制

  • 进程
    • 地址空间(代价巨大)
      • 页表寄存器
      • TLB全部失效:同时新进程初期缺页率高
      • Cache全部失效、有些需要写回
  • 线程
    • PC、寄存器、堆栈

2.3同步与互斥

2.3.1基本概念

临界资源
  • 一次仅允许一个进程使用的资源
  • 许多变量、数据、公有队列、私有数据等,还包括很多物理设备,如:打印机
  • 访问过程
    • 进入区:“上锁”
    • 临界区/临界段:访问临界资源的那段代码
    • 退出区:“解锁”
    • 剩余区:代码中剩余的部分
同步(直接制约关系)
  • 源于相互合作
  • 两个或多个进程之间有先后次序
互斥(间接制约关系)
  • 源于互斥访问
  • 进入临界区使用临界资源的进程有且只有一个
  • 准则
    • 空闲让进
    • 忙则等待
    • 有限等待
      • 在有限时间内,让请求访问的进程进入临界区
      • 保证进程不会“饥饿”
    • 让权等待
      • 当进程不能进入临界区时,应立即释放处理器,防止进程忙等
      • “占着茅坑不拉屎”

2.3.2实现临界区互斥的基本方法

软件实现方法

单标志法——turn
  • 算法思想
    • 每个进程进入临界区的权限只能被另一进程赋予
    • 两个进程交替进入临界区
  • 设置一个turn来指示被允许进入临界区的进程编号表达“谦让”
  • 优点:实现简单
  • 缺点:违背“空闲让进”,造成资源无法充分利用

在这里插入图片描述

双标志先检查法——flag[]
  • 算法思想
    • 每个进程访问临界区前,先检查临界资源是否被访问,空闲才可进入
    • 先“检查”,后“上锁”
  • 设置一个布尔类型的数组flag[i]=false/ture表达“意愿”
  • 优点:不用交替进入可以连续使用
  • 缺点
    • 两个进程可能同时进入临界区,==违背“忙则等待”==原则
    • 检查和上锁无法一气呵成

在这里插入图片描述

双标志后检查法——flag[]
  • 算法思想
    • 先“上锁”,后“检查”
  • 设置一个布尔类型的数组flag[i]=false/ture表达“意愿”
  • 优点:避免两个进程同时进入临界区
  • 缺点:双方可能会相互谦让,导致饥饿,违背“空闲让进”“有限等待”

在这里插入图片描述

Peterson算法——turn+flag[]
  • 算法思想
    • 结合双标志法、单标志法的思想。如果争夺,则谦让
  • 设置一个turn,用来表示优先让哪个进程进入临界区,表达“谦让”
  • 进入区
    • 主动争取
    • 主动谦让
    • 检查对方是否也想使用,且最后一次是不是自己说了"客气话"——联想:给压岁钱
  • 优点:解决了进程互斥问题,遵循了空闲让进、忙则等待、有限等待
  • 缺点:违背“让权等待”,会发生“忙等”

在这里插入图片描述

硬件实现方法

中断屏蔽方法
硬件指令方法
  1. 优点

    • 适用于任意数目的进程,而不管是单处理机还是多处理机
    • 简单、容易验证其正确性
    • 可以支持进程内有多个临界区,只需为每个临界区设立一个布尔变量
  2. 缺点

    • 进程等待进入临界区时要消耗处理机时间,不能实现"让权等待"
    • 从等待进程中随机选择一个进入临界区,有些进程可能一直选不上,从而导致**“饥饿”**现象
TestAndSet指令(TS/TSL)
  • 是原子操作,不允许被中断
  • 为临界资源设置一个共享布尔变量lock(ture/false),表示临界资源是否被占用
  • 优点:实现简单,适用于多处理机环境
  • 缺点:不满足“让权等待”,暂时无法进入CPU的进程会占用CPU并循环执行TSL指令,从而导致==“忙等”==
Swap指令
  • 功能:交换两个字(字节)的内容
  • 优点:可以简单有效地实现互斥

2.3.3互斥锁

  • 布尔值True和False两种状态表示有无被使用,来实现进程互斥;
  • acquire()获得锁,release()释放锁——均为原子操作;
  • 常用硬件机制来实现;
  • 特性:
    • 忙等,进程时间片用完才下处理机,违反“让权等待”;
    • 通常用于多处理机系统,上锁时间短;

2.3.4信号量

  • 只能被两个标准的原语wait(S)–Psignal(S)–V访问
整型信号量(S)
  • 表示当前系统中可用的资源数
    • wait(S):相当于“进入区”,S=S-1
    • signal(S):相当于“退出区”,S=S+1
  • 未遵循“让权等待”,使进程处于==“忙等”==的状态
记录型信号量(S)
  • 遵循了“让权等待”原则,不存在“忙等”现象,用一个进程链表L,链接所有等待该资源的进程
wait操作——申请资源:S.value–
  • S.value < 0时,
    • 调用block原语
    • 自我阻塞,放弃处理机,并插入阻塞队列,运行态——阻塞态
    • 可用资源数=0,等待资源的进程数=|S.value|
signal操作——释放资源:S.value++
  • 若S.value++ ≤ 0,
    • 表示S.L中仍有等待该资源的进程被堵塞
    • 调用Wakeup原语,唤醒第一个等待进程
  • 若S.value=0,
    • 可用资源数=0,等待资源的进程数=0
  • 若S.value>0,
    • 可用资源数=S.value,等待资源的进程数=0
利用信号量实现同步
  • 前V后P,让各并发进程按要求有序地推进
  • 初始值根据可用资源数来确定
利用信号量实现互斥
  • 用一对PV夹紧访问内容,中不能有其他冗余代码
  • 分析并发进程的关键活动,划定临界区
  • 对不同的临界资源设置不同的信号量
  • 用**互斥信号量(mutex)**表“进入临界区的名额”
    • 缓冲区大小=1,可能可以不用mutex
    • 初始值一般为1
利用信号量实现前驱
  • img
分析进程同步和互斥问题的方法步骤

​ 关系分析——整理思路——设置信号量

2.3.5管程

管程的定义
  1. 更方便地实现进程同步与互斥
  2. 保证了进程互斥,由编译器自动实现进程的同步与互斥,降低了死锁发生的可能;
  3. 把对共享资源的操作封装起来(类似Class)
  4. 每次仅允许一个进程进入管程,从而实现互斥
  5. 管程是进程同步工具,解决信号量机制大量同步操作分散的问题
  6. 管程是被进程调用的,是语法范围,无法创建和撤销
管程的基本特征
  • (局部于管程的)数据只能被(局部于管程的)过程所访问
  • 一个进程只有通过调用管程内的过程才能进入管程访问共享数据
组成
  • 管程的名称

  • 局部于管程内部的共享数据结构说明

  • 对该数据结构进行操作的一组过程(函数)

  • 对局部于管程内部的共享数据设置初始值的语句

条件变量(等待序列)
  • 本身没有值,实现进程同步,常配合锁使用

  • 资源数用别的变量记录,判断后调用条件变量

  • wait(等待):释放管程的使用权,即让出“入口”;阻塞进程

    signal(唤醒):唤醒一个因x条件而阻塞的进程

  • if( a < 1 ) S.wait

    • 如果a<1,进程自我阻塞,插入S队列中
    • 同时释放管程使用权,允许一个其他进程进入
条件变量和信号量的比较
  • 相似点:条件变量的wait/signal操作类似于信号量的P/V操作,可以实现进程的阻塞/唤醒
  • 不同点:
    • 条件变量没有值,仅实现了“排队等待”功能;
    • 信号量有值,值反映了剩余资源数;
    • signal操作不会使条件变量值改变,但信号量机制的V操作会使得S.value+1;

2.3.6经典同步问题

生产者-消费者问题
  • 缓冲区没满–生产者生产,缓冲区没空–消费者消费
  • 初始值:mutex=1——互斥信号量,full=0,empty=1;

生产者-消费者问题

  • 实现互斥的P操作一定要在实现同步的P操作之后,否则死锁

    semaphore mutex=1;
    semaphore empty=n;
    semaphore full=0;
    producer(){
        while(1){
            生产一个产品;
            P(empty);                //empty--,获取空缓冲区单元
            P(mutex);                //mutex=0,进入临界区
            把产品放入缓冲区;
            V(mutex);                //mutex=1,退出临界区
            V(full);                 //full++,满缓冲区数加1 
        }
    }
    consumer(){
        while(1){
            P(full);                 //empty--,获取满缓冲区单元
            P(mutex);                //mutex=0,进入临界区
            从缓冲区取出一个产品;
            V(mutex);                //mutex=1,退出临界区
            V(empty);                //empty++,空缓冲区数加1 
            使用产品;
        }
    }
    
多生产者-多消费者问题
  • 缓冲区为1,因此即使不设置专门的互斥变量,也不会出现多个进程同时访问盘子的现象;
  • 若缓冲区>1,则需要设置mutex,否则导致两个进程写入缓冲区的数据相互覆盖的情况;

多生产者-多消费者问题

  • dad(),daughter(),mom(),son()必须连续执行
读者-写者问题
哲学家进餐问题
吸烟者问题
  • 可生产多种产品的单生产者—多消费者

2.4死锁

注意与“饥饿”的区别

2.4.1死锁的概念

  • 多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都无法向前推进

死锁产生的原因

  1. 系统资源的竞争
  2. 进程推进顺序非法:请求和释放资源顺序不对、信号量使用不当;
  3. 必要条件(同时满足):互斥条件不剥夺条件请求并保持条件循环等待条件

2.4.2死锁的处理策略

死锁预防(不允许死锁发生的静态策略):破坏必要条件
破坏互斥条件(无法破坏)
  • 非共享资源:SPOOLing技术——假脱机技术
  • 有些场合应该保护这种互斥性
破坏不剥夺条件
  • 实现复杂,增加系统开销,降低系统吞吐量
  • 不满足全部资源时,直接释放所有
  • 常用于易于保存恢复的资源,如寄存器和内存,不能用于打印机等;
破坏请求并保持条件
  • 预先静态分配全部资源
  • 系统资源浪费严重,资源利用率极低,会导致**“饥饿”**现象
破坏循环等待条件
  • 限制了新类型设备的增加,给用户的编程带来麻烦
  • 顺序资源分配,按编号递增申请资源,造成资源的浪费
死锁避免(不允许死锁发生的动态策略):防止系统进入不安全状态

需要进程运行所需的资源总量信息,死锁检测不需要

系统安全状态
  • 系统按经常推进顺序为其分配其所需的资源,直至满足每个进程对资源的最大需求,使每个进程都可顺序完成。
  • 系统处于安全状态便可避免死锁,进入不安全状态,可能进入死锁
银行家算法

🐔选择题25、27、28

  • 防止进入不安全状态
  • 用于判断系统的不安全状态,无法判断是否处于死锁状态,死锁用死锁定理判断
  • 流程:假设分配,然后检查安全性
  • 注:不会限制申请顺序
死锁的检测及解除(允许死锁发生)

不限制,但能检查错误并解除

资源分配图(描述)

死锁定理:资源分配图不可完全被简化,则存在死锁

死锁的解除资源剥夺撤销进程进程回退

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值