考研408《操作系统》复习笔记,第二章《2.3.3 + 2.3.4 经典同步问题、管程》

一、经典互斥、同步问题

1、生产者消费者问题

1)概念

说人话:

  • 也就是对【同一数据缓存空间】
  • 【输入数据的进程(生产者)】和【获取数据的进程(消费者)】需要互斥、同步的进入这个空间

其中:

  • 【互斥】:同一时刻各进程(不管是生产者还是消费者),都只能互斥访问缓冲区这个临界资源,只允许一个进程进去
  • 【同步】:
    • 【生产者】要等缓冲区不满才可以存数进缓冲区,也就是要等【消费者】取数
    • 【消费者】要等缓冲区不空才可以从缓冲区取数,也就是要等【生产者】存数

2)实际实现逻辑

提示,个人认为概念需要改一下,这里记住:

【关于同步问题】

  • 【对于 "生产者" 视角】
    • empty】=【未满的缓冲区的空间】,就是【可用的临界资源数量
      • 初始值是N,因为还没存数进去还是空的,还有N个可用空间资源
      • 当【生产者】存数时,就会使用【可用空间资源】,【empty--】【full++】
      • 直到【empty<0(full=N)】,【生产者】没有【可用空间资源】了
        • 【生产者】就需要**【消费者"V操作"】来释放** 【empty这个资源信号量
  • 【对于 "消费者" 视角】
    • full】对消费者而言,【可取的数据(暂时当1个数据对应1个空间)】就是【可用的临界资源数量
      • 初始值是0,因为还没存数进去还是空的,消费者有0个数据资源可以取
      • 当【消费者】取数时,就会使用【可取数据资源】,【full--】【empty++】
      • 直到【full<0(empty=N)】,【消费者】没有【可取数据资源】了
        • 【消费者】需要**【生产者"V操作"】来释放** 【full这个资源信号量

【关于互斥问题】

  • 【mutex】=【不管任何进程,控制所有进程可以访问资源的信号量】
  • 互斥针对的所有进程,不管你是生产者还是消费者,一视同仁!!!!
  • 那么做法就是跟之前学的【信号量实现"互斥"】一样:
    • mutex初始值为1
    • 在每一个进程里【P(mutex) ---> 使用资源 ---> V(mutex)】

【合起来完整代码】

注意:【互斥代码】只能被【同步代码】里包着

2、多生产者、多消费者

1)概念

就是4个原则:

  • 1、【互斥】
    • 依旧最基本的原则,同一时刻对"盘子"这个资源,不管是放水果、取水果,只能允许1个进程访问,因此需要互斥访问
  • 2、【同步】
    • 1)女儿要等父亲放苹果后,再取苹果
    • 2)儿子要等母亲放橘子后,再取橘子
    • 3)父母都要等儿子或女儿取走水果,盘子空了才可以放入水果

【提示】:

在分析这个问题的时候要做到:

  • 1、分析每1个进程执行某个事件后,会引发其他进程干什么?
  • 2、将这些关系整理后,一定要按照【事件】的形式分析

2)实际实现逻辑

【同步关系】:如图

  • 对于如何【让儿子吃母亲的橘子,而不吃父亲的苹果】、【让女儿吃父亲的苹果,而不吃母亲的橘子】
    • 最简单就是2个不同的信号量参数就行了,每对关系用各自的信号量控制约束
  • 对于【让父母先等"儿子 or 女儿"取空盘子,再放水果】
    • 就统一用plate这一个变量来控制约束就好了
  • 别忘了同步操作是:前V后P(前操作后面V,后操作前面P)

【互斥关系】:如图

都是老套路了,我就不再多说

【注意!!】

  • 多生产者、多消费者的一个特殊性质:
    • 1、【缓冲区容量只有1时】:"有可能/可以"不设置互斥信号量mutex,也可以天然实现互斥
    • 2、【缓冲区容量大于1时】:绝对不可以不设置互斥信号量mutex,不然会死锁
      • 如果无法理解这个流程,那就记住这个性质就行了。。。。

3、读者、写者问题

1)概念

人话:

  • 1、情况:有读者和写着两组进程并发访问一个【共享文件(数据空间)】
  • 2、首先区分【读者】和【消费者】区别:
    • 【消费者】读取数据的时候,会把数据直接拿走!!
    • 【读者】只读不取,他不会动数据,只安安静静读,所以其实可以多个读者一起读
  • 3、要做的原则是:
    • 允许:
      • 【多读者】:允许多个读者同时读,访问数据空间
    • 不允许:
      • 【1读1写】:1读进程 和 1写进程并发执行
      • 【2写】:2个写进程同时

2)实际实现逻辑

【1.0版本】:解决简单的【一写一读互斥】

  • 1、设置【rw】一个参数,用于一读一写2个进程之间互斥访问
  • 2、解决了:【不允许1读1写】问题
  • 3、但是出现:无法实现【多读者同时读】问题,因为mutex<0,在执行V操作前,其他所有读进程执行P操作都会被卡着

【2.0版本】:【一气呵成前提下解决 "多读进程同时"】

  • 1、多一个参数信号量【count】,统计读进程数量
    • (目前有rw、count两个参数)
  • 2、写进程不变、读进程在P(rw)和V(rw)前后进行【count的检测】
    • 这样做可以让【第一个进入的读进程 P(rw)上锁】、【最后一个结束的读进程 V(rw)解锁】
    • 除了第一个读进程,其他读进程都可以跳过P(rw)操作之间读文件!!!
  • 3、"有限制条件"地解决了【多进程同时读问题】
    • 前提是:必须第一个读进程【P(rw)】和【count++】一气呵成,否则【其他读进程依旧count=0】

【3.0版本】:【读进程优先,写进程饿死】

  • 1、再继续加参数信号量【mutex】,专门针对【count变量 的 "互斥"访问】
    • (目前有rw、count、mutex 3个参数了)
  • 2、写进程不变,读进程在【判断count】前后【包上P(mutex)、V(mutex)】
    • 这样强制保证了只有第一个进程成功把【count++之后(V(mutex)解锁)】,第二个读进程才能获得【非0的count】
  • 3、缺点就是【写进程饿死,读进程优先】
    • 连续并发的读写操作下,只要不断有读进程进入,就要等很久才能让【最后一个读进程】去【V(rw)解锁】,【写进程】一直不能【P(rw)】使用

【4.0版本】:【读写公平(最完美版本)】

  • 1、再加参数信号量【w】,强制让写进程不被读进程打扰
    • (目前4个参数:rw、count、mutex、w)
  • 2、写进程最外层包着【对w的PV互斥】、读进程在mutex前后包着【对w的PV互斥】
    • 假设【读 ------> 写 ------> 读】
      • 这样首先【读进程1:P(w)上锁】,【写进程】等;
      • 【读进程1:V(w)解锁】,【写进程:P(w)上锁】,此时新的【读进程2】只能被迫等待写进程
      • 直到【写进程:V(w)解锁】,【读进程2】才能用
    • 而且因为写进程可以正常执行,因此【1个读进程内的 count变量】基本可以正常自己读完后count--=0,于是一个读进程【自己上锁、自己解锁】

最后完整代码逻辑:

3、哲学家问题

1)概念

官方描述

说人话,按我画的图片理解:

反正你不需要知道这个哲学家跟实际进程运行究竟有什么关系,因为没人知道,我也不知道,不知道哪个人才想出来的,记住下面的概念就行

然后问题就是:

  • 1、【哲学家"吃饭"】需要用左右2个临界资源、【哲学家"思考"】不用资源
  • 2、每个哲学家如何互斥使用左右资源,才能避免死锁?比如【0号哲学家拿了0、1两个筷子】,【1号哲学家想要1号筷子】,【4号哲学家想要0号筷子】咋办?

【初始版本1.0】

  • 1、定义筷子资源的数组,然后在每一个哲学家进程里使用
  • 2、每一个哲学家进程里有【吃饭】和【思考】
    • 【吃饭】的时候要互斥访问
      • 所以先【P(左筷子)】再【P(右筷子)】
      • 然后【吃饭】
      • 最后再依次【V(左筷子)】、【V(右筷子)】
    • 【思考】就啥也不用,纯自己思考就行了
  • 缺点:所有进程【P(右筷子)】时发生死锁:
    • 因为每个【哲学家编号i】都不一样,对应的【P(左筷子i)】也不一样,所以所有进程并发的时候,互不影响都可以拿走左筷子资源
    • 可是再【P(右筷子)】的时候就会发生死锁,所有进程互相等右边进程【V(左筷子)】,问题是没人能执行到这一步啊.....

2)实际实现逻辑

【第一种:官方写法】

没什么好说的,超级简单:

  • 1、依旧沿用上面所有问题的解决方式:
    • 一个进程的所有资源都拿到手之前,全部用mutex上锁:【添加semaohore mutex=1】
  • 2、在一个进程【P(左筷子)】、【P(右筷子)】之前【P(mutex)加锁】,然后再【V(mutex)解锁】就好了

【第二种:复杂题骗分法】

网上一个博主教的,在遇到更复杂的题,所需资源不止【左筷子】、【右筷子】时,可以用此方法骗分

各位自己理解吧,实在不理解就背熟这个模板就好了

实际例题:

结合以上例子我们可以发现:

【哲学家吃饭】问题可以适用于解决各个进程所需资源不止一个的情况!!

4、总结

二、管程

1)是什么

人话:为了解决前面大量繁琐的【PV操作】,而统一设定的【处理同步互斥的接口函数】

无需程序员关心内部是如何实现互斥同步的逻辑,只需要之间调用函数就行

2)管程的结构组成(类似JAVA面向对象类)

  • 解释混淆概念:【局部与管程内部的共享数据结构说明】VS【对局部于管程内部共享数据结构设置初始值的语句】
    • 【局部与管程内部的共享数据结构说明】:
      • 就是定义变量,没包含赋值(例:int a;)
    • 【对局部于管程内部共享数据结构设置初始值的语句】:
      • 给变量赋值了(例:a=0;)

对比JAVA的类:

例题:

3)管程特性

就记住:

解释:

  • 1、也就是管程内的【局部变量】外部不可以修改访问,只能通过管程内的【特定函数】来修改、访问
  • 2、管程【自身就是互斥的资源】!!!各个外部进程想用它,也得互斥使用!!!
  • 3、注意:【管程】与【信号量机制】存在不同处
    • 【前面学的PV操作】:
      • 不仅更改进程的【阻塞、唤醒就绪状态】,还会【更改信号量值】
    • 【管程】:
      • 只更改进程的【阻塞、唤醒就绪状态】,不会【更改信号量值】!
    • 例子:
相关推荐
sulikey1 小时前
操作系统磁盘 I/O:为何选择“块“而非“扇区“?
linux·操作系统·io·磁盘·磁盘io
前端小马1 小时前
PTE考试笔记
笔记·英语
m0_46644103詹湛3 小时前
FPGA时序优化与高速接口实战手册
笔记·学习·fpga开发·硬件架构·verilog
问心无愧05133 小时前
ctf show web 入门39
android·前端·笔记
Yeh2020583 小时前
Mybatis笔记一
java·笔记·mybatis
羊群智妍3 小时前
2026 AI搜索优化技术:GEO监测工具选型与应用
笔记
半导体守望者3 小时前
MKS elite 300 600 750W RF Plasma Generator 射频电源 OPERATIONMANUAL
经验分享·笔记·机器人·自动化·制造
05候补工程师3 小时前
【线性代数笔记】初等变换、正交化与特殊矩阵性质核心总结
经验分享·笔记·线性代数·考研·矩阵
Heartache boy4 小时前
野火STM32_HAL库版课程笔记-I2C介绍
笔记·stm32·单片机