【408 操作系统】第二章 进程与线程 更新完毕

第二章 进程与线程

2.1.1 进程的概念、组成与特征

2.1.1 进程的概念、组成与特征.pdf

本节总览
image.png

  1. PCB + 程序段(指令序列) + 数据段(数据、变量)
  2. 特征:动态、并发、独立(独立获得资源、独立接受调度) 异步、结构
  1. 进程是系统进行资源分配和调度的一个独立单位 (学了线程后,线程是 真正的调度单位,但资源分配的单位仍是进程)
  2. PCB 记录进程信息:status, envs context,cpu info,res
  3. 特征:五大特性,重要的有动态性,独立性,异步性

程序是静态的,进程是动态的
给进程拍快照,得到的就是进程映像(某一时刻的进程信息)

PID —— 进程的身份证
image.png

PCB —— 你的所有信息都被刻在了PCB上!!!

PCB —— 有关于进程的详细信息
image.png

有印象即可

进程的组成 —— PCB + 程序段 + 数据段
image.png

PCB 给操作系统用
程序段、数据段 给进程用

程序的运行 与 进程的创建
image.png
程序或数据属于某个进程?
严格来说 ,进程是动态的;进程实体(映像)是静态的,相当于快照

image.png
再次反思,PCB 是给系统用的,程序段和数据段是给进程本身用的
PCB 是进程存在的唯一标志

2.1.2 进程的状态与转换、进程的组织

2.1_2_进程的状态与转换、进程的组织.pdf
本节总览
image.png

  1. 进程有几种状态? 5 = 3+ 2
  2. 就绪态和阻塞态的区别:就绪态万事俱备,只欠cpu;阻塞态,缺其他资源或事件
  3. 进程状态间的转换:
    1. 就绪态 -> 运行态。 进程被调度,cpu 竭诚为您服务!
    2. 运行态 -> 就绪态。服务结束,请您先暂作休息。
    3. 运行态 -> 阻塞态。 没有系统资源,或主动等待一个事件发生。
    4. 阻塞态 -> 就绪态。 就等你pua了。不对,就等你cpu了

New and ready
image.png

  1. 进程正在被创建,那就是创建态 New
  2. 进程被创建完成,其他资源也分配给它了,但CPU资源还不能给它,便进入“就绪态”Ready

Are you ready? Come on~~

运行态 Running
image.png
cpu 正在为您服务

阻塞态 Block
image.png

  1. 等待系统其他资源的分配,或等待其他进程的效应 (有CPU资源,但却一些其他的系统资源)

我等待的外卖还没来~ 还不能上车。

终止态 terminated
image.png

exit 886

一鲸落万物生。不带走一片尘土。

进程状态的转换关系图
image.png

还没进入状态的 UNUSED

  1. 正在创建的 EMBRYO
  2. 整装待发的 RUNNABLE
  3. 正在运行的 RUNNING
  4. 晚高峰堵车的 SLEEPING
  5. 即将逝去的 ZOMBIE

5 = 3 + 2
image.png

  1. 为什么分成3 + 2
  2. state 记录进程状态

进程的组织 —— 链接方式
image.png
像不像线性表??像不像队列?

image.png

进程的组织——索引方式
image.png
有点像hash 表

2.1.3 进程控制

2.1_3_进程控制.pdf
本节总览
image.png

  1. 进程控制,控制的是什么? 控制的是进程的转态转换。
  2. 为什么原语那么重要?原语的应用场景?原语的实现原理 ?
    1. 原语,一气呵成,不可被中断,所以其具备可靠性。
    2. 原语的重要应用场景就包括本节要学的,进程的状态转换。
    3. 原语的实现原理—— 关中断与开中断之间的程序执行 不可被打扰

image.png

提问:为什么用原语?原语的实现原理是什么?
答:原语执行后将一气呵成,不可中断;原语利用了开、关中断

image.png

提问:为什么需要用到原语?如果不用原语会出现哪些翻车的情况?
答:原语一气呵成;如果不用原语,有可能会存在 进程状态字被修改,但所处队列还没改过来的情况。

image.png

提问:如何实现原语?
答:“关中断”到“开中断”之间的所有指令都不会被中断所干扰,这些指令会被cpu一气呵成地执行。期间接受的中断,会在开中断指令执行后才被处理。

image.png

cpu 执行关中断指令后,就不会再检查/例会中断信号。直到执行开中断指令后才会恢复中断检查。

image.png
创建原语

提问:什么情况下会创建进程?
答:
用户登陆:分时系统,用户登陆成功。(java 中学过多线程,用户登陆会创建一个新的线程,可以类比一下)
作业调度:多道批处理系统,为进入内存的新作业创建新进程
提供服务:操作系统创建新的进程为用户提供服务
应用请求:创建子进程

image.png
撤消原语

提问:什么情况下会终止进程?
答:
正常结束:exit
异常结束:exception 整数除以0等异常
外界干预:用户主动杀死进程 ctrl + alt + del

image.png
阻塞与唤醒原语

为什么阻塞原语和唤醒原语必须成对使用啊?
阻塞原语干了啥?
找到pcb
保护进程的现场,将state 设置成 阻塞态
将pcb 插入相应事件的等待队列
引起阻塞的原因
等待系统分配资源
配合其他进程
等待事件
进程的唤醒要干啥?
在阻塞队列中找到pcb
state 改为就绪态
将pcb 挪到就绪队列,等待被调度
何时被唤醒?
等待的事件发生了!

image.png
切换原语
:切换原语,是在运行态和就绪态之间的切换。前面的阻塞与唤醒,是在阻塞态和就绪态之间转换。
切换原语要保存运行环境的上下文。例如,切换前一时刻的PSW,PC 等寄存器 的值。

All in All
image.png

image.png

2.1.4 进程通信 IPC

2.1_4_进程通信..pdf
本节总览
image.png

什么是进程间通信?
进程间的数据交换。如微博的吃瓜文转发到微信。

为什么进程通信 需要操作系统支持?
因为进程的资源是操作系统分配的,且为了保证进程的安全,所以需要在操作系统的支持下才能完成进程间通信。

进程间通信的3种方式之共享存储

共享存储

image.png

共享存储:在内存种划分一块共享的空间,各线程互斥地访问,能实现进程间通信的效果。

共享存储有低级与高级之分
低级——基于数据结构的共享
高级——基于存储区的共享
前者慢;后者快
image.png

消息传递

消息传递还分为直接通信信箱通信

直接通信方式
image.png

进程p 发信息

image.png

将信息挂载到进程Q 的消息队列

其实这个非常像ros 里面的进程通信
还有老韩的java基础,qq聊天项目中的多线程通信也是类似的实现,即规定一个消息格式/接口,每个线程的消息都必须遵循该格式

image.png

进程Q 取走信息

信箱/间接通信
image.png

进程p 发信息

image.png

信箱接收信息

image.png

进程Q 从信箱中取信息

注意:信箱在内核中

管道通信

pipe
I have an apple and I have a pie.I have an apple pie.
image.png

总结
三种通信方式——共享存储(基于数据结构+基于存储区)+ 消息通信(直接+信箱)+ 管道通信
都需要操作系统的支持

2.1.5 线程的概念

其实关键之处,还是并发的颗粒度问题。没有引入线程,并发的颗粒就是进程;引入线程后,颗粒是更细的线程。

提问:什么是线程? 为什么要引入线程?进程vs 线程?可不可以类比进程?

最初没有进程。程序只能依次串行执行。qq,网易云,只能串行执行,上qq就不能网易云,呜呜~

引入进程后。qq,网易云可以并发执行了,也即可以一边上qq,一边网易云,呜呜呜~

一边网易云,一边qq,这个问题解决了。但新的问题又来了。

刚开始,qq只有一个文字聊天功能,后来功能不断丰富,可以一边文字聊天一边视频或传输文件。

但是,问题来了,此时没有线程这个东西。所以实际的情况下,在qq当中,当你处于文字聊天,你就不能视频,或者视频时,你不能传输文件。狗子心理憋屈啊,qq功能如此丰富了,但是功能却不能同时使用,只能串行地使用。  如果qq里面也能同时使用这些功能就好了。就像一边上qq,一边网易云~

引入线程!

进程可以并发,进程内的线程也可以并发;就像qq和网易云可以同时运行,qq中 的视频和传输 文件也可以同时 运行

从此 ,进程是操作系统资源分配的单位,但调度单位 变成了线程

线程可以完全 类比进程去学习。

image.png

想象:一个IDEA进程 同时run 多个程序,就是多线程的鲜活例子

image.png

挑几个比较好的吧
各线程可以占用不同的cpu
线程几乎不拥有系统资源
线程间通信无需系统干预!
系统开销

2.1.6 多线程模型

本节导览
image.png

本节解决的问题

  1. 线程的实现
  2. 多线程模型

用户级线程 —— 弱智的while 循环  —— 优缺点  —— 早期unix

不涉及cpu 变态;快啊;但是堵塞也是真的慢啊

内核级线程

需要处理及切换到核心态 来 管理线程

内核级线程的多线程模型

  1. 一对一
  2. 多对一
  3. 多对多 中庸之道

用弱智的while 循环来实现 用户及多线程
image.png

灵魂四问!
image.png

  1. 用户
  2. 不需要
  3. 不能
  4. 优点:线程切换不需要操作系统的介入,开销很小;缺点:一旦某个线程阻塞,所有线程均不能正常执行。

优化优化!!!

内核级线程
image.png

  1. 由操作系统管理
  2. 需要
  3. 可以
  4. 优点:每个线程都可以拥有一个核,并发能力强,会堵塞;缺点:需要变态,系统开销大

一对一
image.png
一个用户级线程映射到一个内核级线程
优点:并发能力强;缺点:开销大,一对一很奢侈的

多对一
image.png
多个用户线程映射到一个内核级线程(其实和最开始的用户级线程差不多的)
优点:开销小,不需要变态 ;缺点:会阻塞

多对多
image.png
中庸之道
仔细体会:只有获得“运行机会”的一段“代码逻辑,才有机会被处理及执行。

2.1.7 线程的状态与转换

完全类比进程的状态转换三个

就绪   运行

阻塞

PCB vs TCB

image.png

image.png

下处理机
上处理机

2.2.1 调度的概念和层次

调度就是指挥干活

为什么调度分层次?类比军队的规模和调度的规模

低级调度——进程调度(内存-> cpu) 发生频率最高

中级调度——内存调度(外存->内存), 挂起状态(暂时被调到外存)

挂起状态——就绪挂起和阻塞挂起 5 + 2=7 种状态

高级调度——作业调度 (外存 ->内存)

本节导览
image.png

调度的概念
image.png
说白了,就是怎么合理地安排资源

高级调度

外存到内存,对象是作业,颗粒度比较大
image.png

低级调度

内存到cpu,对象是进程,颗粒度较细。从就绪队列中取进程,将处理机分配给它
image.png

中级调度

image.png
挂起状态和挂起队列由此而来

进程地挂起态和七模型
image.png
7 = 5 + 2
2 = 就绪挂起 + 阻塞挂起

挂起和阻塞的区别
进程被挂起,进程被调到外存去了
进程阻塞,此时还在内存中。
可以感性地想象:如果进程只是短暂地得不到满足,则是阻塞态;如果长时间得不到满足,干脆把它放到外存算了,别占着内存空间。

image.png
越低级,发生频率越高。

2.2.2  进程调度的时机 切换与过程 调度方式

调度时机

切换

方式

调度时机

  1. 适合时机
  2. 不适合的时机

蒙蔽概念:临界区,临界资源,操作系统内核程序临界区 看那道真题。。。真蒙蔽

进程调度的方式

  1. 剥夺
  2. 非剥夺

进程的切换

  1. 狭义
  2. 广义

本节导览
image.png

进程调度,就是上一节学的低级调度
image.png

合适时机

  1. 主动放弃
  2. 被动放弃

不行的时机

  1. 处理中断
  2. 原语
  3. 操作系统内核程序临界区(注意:这里特别说明了是内核的;那就意味着还有普通的临界区,然而,普通临界区是可以进行调度的)

上一道真题来剖析临界区这个概念
image.png
补充:临界区和临界资源对应起来的;临界区是访问临界资源的代码片段,既然临界资源要互斥地访问,那临界区也应该互斥地访问。

前者:就绪队列是内核的程序临界资源
后者:打印机是 普通的临界资源
前者会影响到操作系统的正常工作,后者不会。所以前者不能处于进程调度的时机,后者可以。

image.png

进程调度的方式
image.png

非剥夺式,即让当前进程心安理得地下处理机
剥夺调度,当有老大要来的时候,得给老大上处理机器

进程调度与进程切换
image.png

简单地说,进程调度或切换,其实就是确定下一个要上处理机的进程是谁。

进程切换所要完成的事情:1. 保存原来的数据 2.拿出新进程的数据
进程切换有代价,过于频繁,反而会降低系统效率(时间不花在正事——执行上)。

2.2.3 调度器与闲逛进程

调度器(调度程序)  类比,监听器(监听程序)  xxx器,其实就是一段程序嘛

调度器要解决的问题:

  1. 让谁运行
  2. 运行多久

下面的不是调度器要解决的:

何时运行;何时不能运行

调度方式

idle 闲逛(进程)

操作系统很无聊,让idle 来闲逛一下,优先级最低

调度器/调度程序(scheduler)
image.png
调度程序处理的是②和③哦!

  1. 让谁运行 ?调度算法
  2. 运行多久 ? 时间片大小

调度时机——什么时间 会触发”调度程序“?

  1. 创建新进程
  2. 进程exit
  3. 运行进程阻塞
  4. IO 中断发生,唤醒某些阻塞的 进程,它们将假如就绪队列中

方式

  1. 非抢占式: 只有运行进程阻塞或 exit 才会 触发调度程序来干活 (比较优雅)
  2. 抢占式:每个时钟中断或k个时钟中断后 就会触发调度程序 (比较着急 )

image.png
调度算法处理的对象:有线程则是线程,没线程则是进程。

处理机的备胎伙伴——闲逛进程
image.png
反正处理机就不能闲着。

2.2.4 调度算法的评价指标

有哪几个评价指标
5个,慢慢看吧

本节导览
image.png

cpu 利用率

image.png
cpu 实际忙碌时间 / 总时间
要尽量压榨cpu 来干活

系统吞吐量

image.png
单位时间内完成的作业的数量
xx道 / 秒

周转时间

image.png
作业
从提交到完成的时间

平均周转时间

带权周转时间 平均带权周转时间
image.png
带的权是什么?是作业实际运行的时间。

等待时间

image.png
分为进程等待时间作业等待时间
作业等待时间还需要加上作业在外存后备队列中等待的时间
调度算法只会影响作业/进程的等待时间

image.png
提交请求首次产生响应的时间

2.2.5 调度算法1

调度算法的学习思路?

  1. 思想
  2. 规则
  3. 算法针对的对象?作业调度还是进程调度
  4. 抢占or非抢占
  5. 优缺点
  6. 饥饿与否?(进程/作业 长时间得不到服务,饿死了)

用上一节课学到的调度算法的评价指标来评价各种算法的优劣

算法是硬骨头,得啃下

本节总览
image.png
image.png

FCFS 先来先服务算法

image.png

思想:公平
规则:按照到达的先后顺序进行服务
非抢占
优缺点
饥饿:不

image.png
先来先服务 等价于 等待时间越久越优先被服务(好好想清楚,先来的话不就得等久一点嘛)

周转时间 = 完成时间 - 到达时间
带权周转时间 = 周转时间/运行时间
等待时间 = 周转时间 - 运行时间

平均xx 时间 = xx 时间/作业数量

对FCFS的算法评价
image.png
优点:公平,简单
缺点:对长作业有利,对短作业不利。排队买奶茶(第一个人 买30杯,第二个人买一杯,导致第二个人被迫为了一杯奶茶而等待半小时)
不会饥饿

短作业优先法 SJF

image.png
有抢占式和非抢占式之分
抢占式成为最短剩余时间优先法

短进程优先法 SPF

image.png

最短剩余时间优先法 SRTN

image.png

image.png

SPF 和 SRTN 对比

image.png

算法评价

image.png

高响应比优先 HRRN

能不能综合FCFS 和 SPF 的优点呢?

高响应优先 HRRN 来也!
image.png

image.png
注意看相应比,等待时间和服务时间都用上了

算法评价
image.png

2.2.6 调度算法2

本节的调度算法2,视角和算法1的不一样。算法1着重分析各算法的评价指标(周转时间、等待时间等指标)
本节注重现代操作系统(分时OS)下的调度算法的研究。
虽然着眼点不同,但是这两节内容仍然是有联系的。比如本节的时间片调度算法中,当时间片过大时,会退化为FCFS。

本节总览
image.png

还记得吗?学习各种调度算法的学习思路?

  1. 算法思想
  2. 规则
  3. job or process
  4. 抢占式or非抢占式
  5. 优缺点
  6. 饥饿与否?

时间片轮转

image.png

image.png

基于分时系统。时间片
注入队头队尾的插入
抢占式!时间到则强制下机

image.png

自己分析:
p1 p2 p1 p2p3 p4 p1 p4 p4
0 - 2 - 4 - 6 - 8-9 - 11-12 - 14 - 16

  1. p1(3)
  2. p2(2) p1(3)
  3. p1(1) p2(2) p3(1)
  4. p2(0) p3(1) p4(6) p1(1)
  5. **P3(0) **p4(6) p1(1)
  6. **p4(4) **p1(1)
  7. p1(0) P4(4)
  8. p4(2)
  9. p4(0)

** 默认:新到达的比刚下处理机的更靠近队头**

p1 p2 p1 p3 p2 p4 p1 p4 p4
0 - 2 - 4 - 6-7 - 9 - 11-12 - 14 - 16

  1. p1(3)
  2. p2(2) p1(3)
  3. p1(1) p3(1) p2(2)
  4. p3(0) p2(2) p4(6) p1(1)
  5. **P2(0) **p4(6) p1(1)
  6. **p4(4) **p1(1)
  7. p1(0) P4(4)
  8. p4(2)
  9. p4(0)

** 以上我的记法和咸鱼的不太一样**
我每一行首进程括号里记录的是(执行完当前时间片后剩余的执行时间);而咸鱼的记法是记录该时间片执行前的剩余执行时间。

时间片为 2

image.png

image.png

image.png

时间片为 5

image.png

自己分析时间片为5的情形

p1 p2 p3 p4 p4

0 - 5 - 9 - 10 - 15 - 16

换另一种记法(执行前剩余执行时间,本次执行花费的时间)

  1. p1(5,5)
  2. p2(4,4)
  3. p3(1,1)
  4. p4(6,5)
  5. p4(1,1)

image.png

时间片轮转算法的评价

image.png

时间片到了,需要切换进程,进程切换的开销也是重要的衡量指标
努力使切换进程的开销占比低于1%

辩证地看待时间片的过大与过小
时间片过大 ,则退化为 FCFS,对长作业有利,对短作业不利
时间片过小,频繁切换进程,系统开销大

image.png

优先级调度

优先级调度算法有抢占式与非抢占式之分
非抢占式:当前进程主动放弃处理机时发生调度
抢占式:当前进程主动放弃处理机时发生调度 + 就绪队列发生改变时判断是否需要调度

非抢占式

image.png
操作步骤还是比较简单的

抢占式

image.png
抢占式的调度时间节点会比非抢式的更多,所以需要考虑多一点

优先级调度的算法评价

image.png

静态与动态优先级
进程优先级的设置依据(系统 > 用户; 前台 > 后台)
操作系统更偏好 I/O繁忙型进程(I/O 尽早开始工作,越好)
动态优先级的考虑因素:公平、资源利用率、饥饿、IO 频繁程度

image.png
会饥饿

多级反馈队列(各算法优点的集大成者)

有没有集大成者?
有!你爹来了!
image.png

image.png

过程较为繁琐,细品(请配合视频课的动画去理解)
image.png

image.png

2.2.7 调度算法3

多级队列调度

就一张ppt
image.png

分类的思想

  1. 优先级的分类(高 到 低)
  2. 时间片在不同优先级的分配
  3. 优先级固定与否 (是否要等到高优先级的全都执行完才可以执行低优先级的?)
  4. 队列中可采用不同的调度策略

可以很灵活

2.3.1 进程同步、互斥

概念
举例
理解

本节总览
image.png

先概述视频课中两个生动形象地例子(进程同步)

  1. 老渣和一号二号两位女嘉宾约会。一号想成为老渣的初恋,二号想找有恋爱经验的人。这就要求老渣得先把心交给一号,再把心交给二号。这两步顺序不能颠倒。
  2. 进程间的管道通信,先得往管道里写数据,才能从管道中读数据,顺序不能颠倒

以上两个例子都是进程同步涉及的问题

进程互斥的场景举例

  1. 打印机摄像头资源的互斥共享(临界资源的访问 )

提问:进程同步和进程互斥的区别? 他们对应了哪些具体的场景?
答:进程具有异步性,但为了让进程按照我们的意愿去执行,我们得想法设法让进程同步,所以进程同步解决的是进程异步的问题;进程互斥是指不同进程访问同一临界资源,要互斥地访问,不能同时同时一起访问。

进程同步

image.png

进程互斥

image.png

临界资源的概念:同一个时间段内,只允许 一个进程使用的资源
对临界资源的访问:互斥
进程互斥:当一个进程访问某临界资源时,另一个进程也想访问该临界资源,则必须等待。

进程互斥的四个区

image.png

进入区:检查是否可以进临界区:可进,则设置正在访问的标志位(上锁),以告知其他进程不给进
临界区:访问临界资源的那段代码
推出区:解除 正在访问的标志位(解锁)
剩余区:做其他处理
进入区和退出区时负责实现互斥的代码段

进程互斥的原则

image.png

  1. 空闲让进
  2. 忙则等待
  3. 有限等待
  4. 让权等待 (防止自旋等待,忙等待,不然会白白占用处理机)

2.3_2_进程互斥的软件实现方法

谦让和表达意愿
压岁钱!
能否一气呵成
多想想并发的执行会导致什么问题?比如死锁或都可以访问

解决了啥问题,解决不了啥问题?为什么

本节总览
image.png
image.png

实现互斥的四个逻辑部分:

  1. 进入区
  2. 临界区
  3. 退出区
  4. 剩余区

互斥四原则

  1. 忙则等待
  2. 空闲让进
  3. 有限等待
  4. 让权等待

image.png

打印机脑抽

单标志位

只在前面设置一个turn,用来标识可以允许几号进程访问
各进程中有while 循环来不断检查自己能否进入
image.png

image.png

为什么说违反了“空闲让进”原则?
解释:假设P0 进入临界区,执行完后将turn 置为 1。P0还想再进入临界区,但P1进程一直都不进入临界区,导致turn 的值一直是1,P0想再进一次都不行 。一定要等对方将turn 修改为属于我的turn 才可以。
简单地说,就是我想进临界区之前,还得对方同意。对方要是一直不同意,既是临界资源空闲,我也不能访问。

双标志先检查法

不服就加标志!

image.png

搞一个数组,将两个线程的意愿都存进去
访问临界区时修改数组值,访问完也要修改

image.png

为什么说违反了“忙着等待”原则?
终究时扛不住并发的考验!检查和上锁不是一气呵成!
精辟:在“检查”后,“上锁”前有可能发生进程切换。

双标志后检查法

双标志前检查法,会导致两个进程同时进入临界区。这是因为在“检查”后,“上锁”前有可能发生进程切换。
因此,想到先“上锁”后“检查”来试试
while是检查,数组赋值是上锁
image.png

image.png

你终归是扛不住并发的考验!
虽然解决了”忙则等待“问题,但又违背了“空闲让进"和“有限等待”
死锁,饥饿

Peterson 算法

到底有没有好方法啊!!
Peterson 来也!
image.png

单独是turn 或单独用数组都不行,那我两个都用!!!
用数组来表达意愿;用turn 来表达谦让
while 循环条件是 对方的意愿和turn 综合的结果 (只有对方有意愿而且我谦让了,我才会阻塞,给对方执行)

image.png

看最后一次说客气话(改变turn 的值)是谁!

image.png

image.png

现在就只剩让权等待实现不了

2.3_3_进程互斥的硬件实现方法

让权等待
单处理机?多处理机?
一气呵成?
原理类似与否?
时空想象!

image.png

image.png

中断屏蔽方法

image.png

只适用于单处理和操作系统内核进程,因为开/关中断指令只能运行在内核态
开关中断是对一个核而言的

TestAndSet 指令 (TS or TSL)

image.png
要有一定的时空想象
while循环执行得很快!!!一直在试探能不能抢到锁。一旦检测到old 为false,就立马强到锁。
TSL是硬件实现得,这个函数可以 一气呵成!!(实现逻辑和软件一样,但是软件做不到一气呵成)
缺点:还是未能解决”让权等待“这个问题!!

Swap 指令

image.png
如果lock 和 old 交换后,old 为false,则说明lock 为false,即解锁了,此时会推出循环,执行临界区代码。
逻辑上和TSL 差不多

2.3_4_互斥锁

自旋锁 忙等待 让权等待? 占用处理机?
上锁时间短的话

image.png
自旋等待,并不一直占用cpu 资源,时间片到了,会被下机。

image.png

不适用于单处理机,因为忙等的过程不可能解锁?

2.3_5_信号量机制

让权等待!!!之前一直解决不了!
软件解决方案 vs 硬件解决方案

一对原语 wait (P) signal(V)
P V 操作 西班牙语

image.png
image.png
以前的所有方法都无法解决”让权等待“的问题

image.png
原语+软件 = 可以解决”让权等待“

整形信号量

打印机例子
关键是使用了原语机制
还是会导致“让权等待”呀!会发生忙等!

image.png
还是会发生忙等?因为 wait() 的while 循环会一直循环

记录型信号量

好处多多,应用场景也很多;同步和互斥都可以用到记录型信号量

整形信号量会忙等
记录型信号量不会忙等呜呜呜

记录型信号量绝佳!!!好贴心!好有逻辑!自己爽完还会唤醒等待队列
得不到满足的进程会转成阻塞态,排到等待队列中,不会在那傻傻地忙等

image.png
记录型信号量的定义!typedef struct
block()会导致阻塞而不是忙等
wakeup() 唤醒

image.png
这个打印机的例子,最好配合视频的动画来理解会更清晰

image.png
要认真感受和想象对应的情形

2.3_6_用信号量实现进程互斥、同步、前驱关系

信号量对应资源
信号量的值对应资源数量 大于零 小于零 的含义

semaphore的数据结构
阻塞态
mutex 的值
PV 操作是成对的

进程同步是要干啥;同步关系 ,关键是要分清前后关系,一前一后
如果利用信号量机制实现

利用PV对资源S的操作来控制一前一后地执行
S的数值变化

同步操作:前V 后P;V+ P-
PV 操作有可能唤醒别的进程!妙啊

互斥操作初始值为1
同步操作初始值为0
前驱问题其实是多个同步问题的集合
image.png

image.png

image.png
image.png

信号量的含义
信号量的value
P(S) 申请一个资源,会导致 S.value -- ** 如果资源不够就阻塞等待(不是忙等哦)**
V(S) 释放一个资源,会导致 S.value ++ 如果没有进程在等待该资源,就wakeup 一个进程

image.png

  1. 界定临界区资源
  2. 设置互斥信号量mutex 的值
  3. 进入区 P(mutex) —— 申请资源
  4. 退出区 V(mutex) —— 释放资源 (同步问题需要先执行的代码释放资源,后执行的代码才能执行)

注意:

  1. PV 操作成对出现
    1. 缺少P 则不能互斥访问
    2. 缺少V 则有可能不会唤醒别的进程
  2. 对不同的临界资源需要设置不同的互斥信号量,mutex1(摄像头) mutex2(打印机) mutex3(麦克风)

信号量机制实现进程同步

image.png

image.png
进程同步问题的实现:后执行的代码需要得到前执行代码释放的资源(V(S)) 才行

信号量机制实现前驱关系

image.png
其实是多级的同步问题

2.3_7_生产者-消费者问题

生产者消费者问题
解决进程同步问题

生产者 缓冲区(容量为5) 消费者
缓冲区满,生产者阻塞;缓冲区空,消费者阻塞
这是同步问题
一前一后为同步,不能同时为互斥

多个生产者,多个消费者的场景呢?有可能同时操作同一块空间
这是互斥问题

确定PV 操作的顺序来解决上述 问题
什么时候/条件执行P,什么时候/条件执行Q
再设置合理的初始值:mutex 互斥信号量;full ; empty(这一步的初始值设置还是绕的,是0 1 还是n,设置的依据是什么得看具体场景)
互斥信号要设置为mutex,处置一般为1;同步信号按照资源名称来设置

难点:P操作谁?V操作谁?多重PV怎么合理安排?要跳出代码考虑具体的情境才能更好地把握
PV一定要闭合
前驱图 V 携带资源指向 P

能否改变相邻的PV 操作顺序?(要分清是同步的PV还是互斥的PV)
循环等待 死锁的问题
结论:

  1. 实现互斥的P操作一定要在实现同步的P操作之后,不能颠倒,否则死锁;V操作的顺序 可以交换。
  2. 临界区的代码最好不要放到PV操作里面(考虑性能)

image.png
紧紧抓住两个量:产品数量空闲位置(这是两种资源)
注意:**否则必须等待 **

自己分析前驱关系

前驱关系图
image.png

只能说这里的full 和 empty ,起这种名字真的是表意不明,还让人抓狂搞不懂!到底谁full,谁empty;什么时候full什么时候empty 啊!
设置为 product 和 place 不挺好的吗?

p减v加
生产者对产品数量是V 对空闲位置是P
消费者对产品数量是P 对空闲位置是P
一开始,空闲位置为n,产品为0
生产者进程和消费者进程还要实现互斥访问
要看懂这个前驱图啊,并不是什么双向的图。分析:有产品(V 提供产品资源)才可以消费P(消耗产品资源);缓冲区没满(V 提供空闲位置资源)才可以让生产者生产(P 消耗空闲位置资源)

image.png
full 和 empty 在这里是什么含义? 结合这张图,我猜,full 是缓冲区中的产品数量,empty 是缓冲区中的空域位置数量。一开始,full = 0 ,empty = n


和这个图的分析是差不多的

image.png

full 和 empty 在这里是什么含义? 这页ppt 右下角不是有解答吗,前面没发现,真是不应该啊,还自己猜呢,不过也没猜错。

image.png

分别分析生产者和消费进程和互斥访问
生产者:

  1. 生产产品(消耗空闲缓冲区)
  2. 把产品放入缓冲区(增加产品)

消费者:

  1. 从缓冲区取出一个产品(消耗产品 )
  2. 使用产品(增加空闲缓冲区)

以上的顺序不要弄乱

互斥访问
也要提供PV操作

image.png
仔细想象对应的场景!很重要!
当没有空位时,Producer执行了P(mutex),Consumer紧接着也执行了P(mutex),Consumer会因为mutex 而阻塞。Producer执行完P(empty)后被阻塞,因为没有空位置,只能等待Consumer消费一个产品腾出一个空位置,但是Consumer 在mutex 就已经被阻塞了,无法腾出空位置。
现在的局面就是,Producer 需要 空位置,但得不到满足,但又不肯解锁;Consumer 因为没有获得锁,而没办法腾出空位置。相互僵持的局面,谁也不肯退让。

image.png
前驱图!
同步!
互斥!
设置信号量!
死锁问题!

2.3_8_多生产者-多消费者问题

本节提示

有哪些进程
有哪些事件
哪些进程存在同步关系;哪些进程存在互斥关系
思考同步问题的颗粒度?着眼点是“事件”,而非单个进程本身,一个事件可以牵扯很多个进程。

image.png
餐盘只能装一个水果
爸爸往餐盘放苹果;妈妈往餐盘放橘子
女儿从餐盘取苹果;儿子从餐盘取橘子

自己分析 有哪些进程?同步关系?互斥关系?PV 操作

  1. 有四个进程
  2. 考虑同步关系
    1. 爸爸放了苹果,女儿才能拿苹果。一前一后
    2. 妈妈放了橘子,儿子才能拿橘子
  3. 考虑互斥关系
    1. 不能同时访问餐盘
  4. PV 操作和PV 前驱图
    1. 明确有哪些资源
      1. plate 餐盘空闲容量,初试是1(进程互斥问题,初始值为1)(这里的plate是指盘中可以放多少水果,而不是互斥问题)
      2. 苹果数量 apple,初始是0
      3. 橘子数量 orange,初试是0
      4. 还有互斥变量mutex要设置
    2. PV 操作的安排
      1. 对于plate 餐盘容量,爸爸和妈妈需要在while 循环中 P(plate),对餐盘进行P 操作;女儿和儿子取走水果后对餐盘进行 V(plate)操作
      2. 爸爸往餐盘放apple V(apple),女儿从餐盘取apple P(apple)
      3. 妈妈往餐盘放orange V(orange),儿子从餐盘取orange P(orange)

image.png
同步:前V后P
注意同步的P 要在互斥的P 前

image.png
提问:可不可以不用互斥信号量?
答:此处可以,因为mutex = 1;

image.png

image.png
容量为2,则可能进程同时访问同一块空间

image.png

image.png

思路整理
image.png

同步问题的思考粒度——以事件为着眼点
image.png

2.3_9_吸烟者问题

取模
P阻塞 V给资源
同步问题

image.png
三个抽烟者进程,一个供应者进程
每个抽烟者都缺一个独特的组合;供应者每次提供一个独特的组合
抽烟者抽完烟会给提供者一个信号

image.png

同步问题

  1. 吸烟者须得到供应者提供给它的组合,才能抽烟(一前一后)
  2. 供应者接收到吸烟者吸完的信号后,才继续提供组合(一前一后)

互斥问题
此处暂不考虑互斥问题

image.png
同步问题,先V 后P

image.png
是否需要专门设置一个互斥的信号量,这个问题多生产多消费者的时候遇到了,如果多个进程最多只有一个可以访问缓冲区,则不需要。

image.png

2.3_10_读者写者问题

本节专注于互斥问题
本节的思想精华是设置互斥变量来实现一气呵成的效果

image.png

  1. 允许多个读者同时对文件执行读操作
  2. 只允许一个写者执行写操作
  3. 任一写着在完成写操作之前都不允许其他读者或写着工作
  4. 写着执行完写操作前,应让已有的读者和写着全部退出

image.png
本节主要分析读写进程的互斥关系。
互斥信号量初值一般设为1
互斥关系:写-写;写-读

image.png

image.png
这里没加mutex 互斥变量会出现没办法同时读的问题;因为对count 的检查和赋值 无法一气呵成(所以需要增加互斥变量 mutex)

image.png
写进程饿死

image.png
再次添加一个互斥变量w,来解决写进程饿死问题
“读写公平法”

image.png
思想的升华

2.3_11_哲学家进餐问题

哲学家问题和前面的不同之处在于,该问题涉及一个进程同时请求两个临界资源

image.png

image.png
死锁原因

image.png

image.png

image.png

image.png
看看2号哲学家,虽然他本可以拥有两个筷子,但还是被阻塞了!这就是这个解决方案的关键所在

image.png
更准确的说法!

image.png

2.3_12_管程

image.png

引入管程,方便程序员实现进程/线程的互斥、同步
思想:封装的思想,封装成数据结构、类、方法等;然后对外暴露接口。用函数封装了最原始的PV 操作,程序员只需调用函数即可,进程互斥、同步由编译器来处理
实战:用管程来解决生产者消费者问题;java 中 的 synchronize 关键字

image.png

image.png

如果按最原始的方式来实现同步、互斥,则需要合理地安排各种PV 操作,容易出错,且效率低。

image.png
管程的定义类似java 的类,类中有数据结构(定义的数据类型)和函数(过程)

数据结构——自定义的数据类型
一组过程——一组函数
初始值——初始化变量
管程名字——类名
管程的基本特征

  1. 管程中的数据只能由管程中的过程所访问。(private 变量,只能由类中的private函数操作)
  2. 一个进程只有通过调用管程中的过程才能进入管程访问共享数据(进程调用类中对外暴露的接口,才能间接访问管程的共享数据)
  3. 每次仅允许一个进程在管程中执行某个内部过程(由编译器实现)

image.png

相当于定义了一个类 ProducerConsumer。
类中有一些条件变量 full、empty,控制变量 count
有函数 insert() 和 remove()
函数中封装了 PV 操作
注意:每个函数中都有signal (),即V 操作,当条件满足时,执行V 操作可以唤醒因等待资源而被阻塞的进程

  1. 如 insert() 函数中,if (count == 1) ,即说明该生产者生产该产品前,缓冲区是空的,它是缓冲区空了之后第一个放产品进缓冲区的,这时对empty 执行signal() 即V 操作来唤醒可能正在等待产品的消费者进程。注意:insert() 函数中,为什么是count ==1 ,而不是count ==0 ,因为count++if (count == 1) 前执行
  2. remove() 函数中, if (count == N -1) ,即说明该消费者取出这件商品前,缓冲区是满的,这时对full 执行 signal() 即V 操作来唤醒可能正在等待空位置的生产者进程。注意:remove() 函数中,为什么 count ==N -1,而不是N呢?因为 count--if (count == N -1) 前执行

image.png

image.png

2.4_1_死锁的概念

吃着碗里的,盯着别人碗里的。
image.png
image.png

image.png
退一步海阔天空,但没有人退

image.png

image.png

死锁,进程争抢资源,不肯退让,导致进程阻塞
饥饿,进程长时间得不到执行
死循环:自己写的无限循环,停不下来,在原地旋转跳跃,闭着眼,傻嗨

死锁的四个必要条件
image.png
四个条件都是必要条件
互斥条件:争夺同一个资源
不剥夺条件:进程已经持有的资源,只有进程自己可以主动释放
请求和保持条件:吃着碗里的,还要抢别人碗里的
循环等待条件
发生循环等待时,如果有一个持有相同资源的局外人愿意贡献自己的资源,那么可以解决循环等待导致的死锁

image.png

常见的发生死锁的时机

image.png
可以类比如何防止工厂火灾:1. 思考起火的必要条件,尽量破坏起火的必要条件:取出可燃物,隔绝氧气等 2.通过合理的工厂布局 3.即使着火了,及时将火灾掐灭在火苗阶段

预防死锁:破坏死锁的必要条件 (静态)
避免死锁:算法支撑 (动态)
死锁的检测和解除:检测+解除

2.4_2_预防死锁

破坏死锁的四个必要条件
前面哲学家进餐问题那一节给出了三个解决死锁的方案,请学完本节后思考那三个解决方啊分别对应了哪些必要条件

image.png

image.png

破坏互斥条件

image.png

把互斥资源做成非互斥资源,这里应用了SPOOLing技术,把独占设备在逻辑上改造成共享设备
缺点:系统安全问题

破坏不剥夺条件

image.png

不剥夺条件:等进程自己主动释放
破坏不剥夺条件可以避免死锁

  1. 方案一:请求不到,则释放持有的全部资源
  2. 方案二:考虑优先级,让操作系统强行剥夺。比如之前学的剥夺调度方式

缺点:

  1. 实现复杂
  2. 释放已有资源,会导致工作记忆丢失
  3. 反复申请和释放资源,系统开销大
  4. 方案一:可能导致进程饥饿

破坏请求和保持条件

image.png

请求和保持条件:吃着碗里的,盯着别人碗里的
静态分配法:一次申请完所需的全部资源,归他所有。
缺点:资源浪费问题;进程饥饿问题

破坏循环等待条件

image.png

循环等待条件:循环链,你爱她,她爱他,他爱我。
顺序资源分配法:顺序编号,不能吃回头草(不能回头申请小编好资源)
缺点:

  1. 不方便增加新的资源,涉及重新编号
  2. 申请资源的顺序和使用资源的顺序不一致,导致资源浪费。(如申请时:先申请5号,再申请7号;使用时:先使用7号,再使用5号)
  3. 必须按次序申请资源,用户编程麻烦

2.4_3_避免死锁(银行家算法) 重点

银行家算法是重点!!!
一定要搞清楚搞明白!
image.png

image.png
安全序列:按某种规则分配资源后,还能顺利回收。这种规则下得到的分配序列就是安全序列

image.png

image.png
安全序列可以不唯一

image.png
不安全序列只是有可能发生死锁,并非一定。但发生死锁,则一定是不安全序列。

image.png
引入向量

image.png

image.png

image.png

银行家算法的代码实现
image.png

image.png

image.png

2.4_4_死锁的检测和解除

如果能结合数据结构的图结构会更好
本节内容还挺有趣

image.png

image.png

image.png

image.png

image.png

image.png
既不阻塞又不是孤点?

image.png

posted @   PigBrither666  阅读(78)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示