[操作系统OS]第九章:信号量和管程

本文介绍了信号量和管程作为进程同步和互斥的工具。信号量通过P和V操作实现资源的访问控制,分为二进制和计数信号量,适用于互斥和条件同步,但也存在易出错和处理死锁的问题。管程则是更高层次的并发控制,结合锁和条件变量,提供了一种更安全的管理共享数据的方法,避免了某些信号量的缺点,确保了正确的同步和互斥。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、信号量


之前通过锁机制,实现了在临界区域内进程的互斥执行。但这个是远远不够的,如果想要实现进程间的同步操作或者实现临界区中多个线程的执行,那么就需要高层次的编程抽象和底层硬件支持。
信号量的抽象数据类型:

  • 一个整形(sem),两个原子操作
  • P(): sem减1,如果sem<0,等待,否则继续
  • V(): sem加1,如果sem>=0,唤醒一个等待的P

image.png
信号量种类:

  • 二进制信号量:实现了lock功能,也就是实现互斥。可以是0或1;也可以实现调度约束:就是一个进程执行到P()进行等待,然后等另外一个进程执行到V()从而唤醒等待的线程,确保同步
  • 一般/计数信号量:可以取任何值。一般条件同步(采用调度约束实现一个线程等待另一个线程的事情发生)

信号量的实现


需要借助于等待队列来完成,对于上述的block和wakeup方法可以看作是入队和出队的步骤。
信号量的用途:互斥和条件同步(注意等待的条件是独立的互斥);
信号量的缺点:读/开发代码困难;容易出错(使用的信号量被另一个线程占用,完了释放信号量);不能够处理死锁;


二、管程

一开始存在于语言层面去控制并发问题,后来才应用于操作系统层面。
目的:分离互斥和条件同步的关注
定义:一个锁(临界区)加上0个或若干个条件变量(等待/通知信号量用于管理并发访问的共享数据)
管程实现的一般方法:收集在对象/模块中的相关共享数据;定义方法来访问共享数据。

所有进程在右上角的排队队列中,排队完后进行wait()操作,等到signal()操作唤醒后,执行这个进程的代码。
组成:

  1. Lock

要么使用锁,对锁进行acquire或者release来抢占或者释放锁

  1. Contion Variable

要么使用条件变量,如果条件不满足wait,就持续等待,一旦满足条件就唤醒队列中的线程继续执行
条件队列实现

wait方法中,numWaiting是一个统计量,统计了有多少线程处于等待队列中,注意这里必须要在先进行release操作之后,才可以执行睡眠等待,不然会触发死锁。一旦唤醒就会立刻抢占锁。
上述是condition的实现,而在管程中带有两个这样的condition:

对于Deposit操作:
对于buffer没有满的情况这边就不讨论,如果buffer已满也就是count == n 时,就会在notFull的Condtion中将一开始加的锁解掉,那么这个时候deposit的线程会进入到condtion中的schedule进行休眠等待。那么remove操作就可以抢占到锁,然后开始从buffer中进行消费,然后唤醒之前睡眠的线程,最后释放锁。
如果这边remove的线程抢不到锁,那么新的抢占到锁的deposit线程就会有又一次进入到wait操作,再次存放于等待队列并且释放锁后休眠等待。
一旦之前的锁被唤醒就会尝试去获取锁,如果获取到了锁,那么外层的count == n 就不会满足所以就跳出了循环,将线程防止于buffer中,等待消费。变更完统计量后,再次去唤醒相同情况下的notEmpty条件等待队列中的线程,最后再释放自己的锁。


总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值