操作系统(thuOS)笔记(十二) 第十八讲 信号量与管程
18.1 信号量
回顾
信号量(semaphore)
操作系统提供的一种协调共享资源访问的方法。
就像球场上,如果没有裁判,都按规则踢,但对规则的理解若有不同,则就会出现问题;因此引入裁判,即OS
类比成铁路
如图的铁路,进来一辆车,sem-1
再来一辆,sem再-1变成0了
再来车发现红灯了,就要等待了
有一辆货车装卸完毕,sem+1,绿灯亮
等待的车进来,红灯亮
信号量的特征
信号量的实现
P操作对信号量减一,如果减没了,就将新进程加到队列q,并阻塞
V操作对信号量加一,如果加了还是小于零,则说明队列里还有在等待的,于是把相应的线程放到就绪队列中,并激活
最大的区别是,操作系统将加减和判断保护起来不被打断,就简单多了
13.2 信号量使用
信号量分类
举例 用信号量实现临界区的互斥访问
用一个信号量对应一个临界区
举例 用信号量实现条件同步
要求在执行完X才能执行N,则下面的形式就可以实现。开始信号量为0,执行M后信号量为-1,N想要执行就必须等待线程B的X执行完将信号量加1变为0
生产者-消费者问题
更实际的例子,比如打印机工作,多个任务被传给打印机,打印机只能接收一个任务
用信号量解决生产者-消费者问题
任何时刻只能有一个线程操作缓冲区(互斥访问);缓冲区空时,消费者必须等待生产者(条件同步);缓冲区满时,生产者必须等待消费者(条件同步)
二进制信号量描述互斥访问,两个资源信号量描述条件同步
看到这儿我看明白了,所谓信号量,就是一个受操作系统保护其加减一的变量,用来反映使用或未使用的情况
小问题:P、V操作可以颠倒吗?答案是不能,这样会造成死锁,因为需要先检查空和满,然后再去申请互斥访问。如果这是已经申请了互斥访问,那别人就不能读写了,而这时发现里面是满或空,自己进行不下去,别人也无法申请。
使用信号量的困难
18.3 管程
从刚才的生产者消费者问题可以看到,PV操作室分散在生产者和消费者两个不同的进程当中,在这种情况PV配对困难。下面要说的管程就是为了把PV放到一起。为了实现管程,增加了条件变量
管程(Moniter)
管程是一种多线程互斥访问共享资源的程序结构
任何时刻只允许一个线程执行管程代码这一点和临界区很像,区别体现在
管程允许在执行过程中临时放弃。就像跑赛车,一个赛道里只允许一辆车在跑,如果正在跑的赛车停下来加油,就允许其他赛车进入赛道
管程的组成
把下面这个结构视为一个管程,如果想视为一个临界区,只需要在共享数据处加一个锁
管程加入了条件变量,这也是和临界区不同的地方
条件变量(Condition Variable)
条件变量的实现
很简单,条件变量和信号量的定义基本类似,
用信号量解决生产者-消费者问题
申请缓冲区时,先看是不是有空地,即看count?=n如果没有空地就要等待Remove释放缓冲区
用信号量时,必须先检查缓冲区的状态,然后再申请互斥操作,在管程里把这个倒过来了,这样没问题吗?原因在于管程在内部检查时如果不成功,还可以放弃访问权限,但是在信号量中,进入临界区,已经占用了别人就进不来了。
那么,是当前管程内部的线程优先执行,还是正占用管程处于执行状态的线程优先执行、
Hansen管程是当前执行的线程更优先,Hoaer是内部的线程优先执行。
选择题,管程也会出现死锁
18.4 哲学家就餐问题
方案1 用信号量解决
会出现的问题是,如果五个哲学家都就餐,那就都拿起了左边的刀叉,此时桌上已经没有刀叉了,所有人都在等待其他人用完,陷入死锁
方案二 任何时刻只有一个哲学家就餐
这种方法正确,但低效,性能不好
方案三 不让哲学家都按先左后右的顺序拿刀叉,如偶数序号的哲学家先左后右,奇数序号哲学家先右后左
没有死锁,可以多人同时用餐
是不是最优的呢?留给大家课后思考
18.5 读者-写者问题
存在于数据库等很多需要共享资源访问当中
同一时刻允许多个读者,读写互斥,写写互斥
用信号量解决读者-写者问题
第一个是读写互斥,也负责写写互斥
第二个是读者技术,用来记正在进行读操作的读者数目
第三个是用来保护读者计数
仔细分析一下
现在来了第一个读者,此时不仅要把读者数加一,还要使写信号量减一就是不让写,读完了读者数减一。这期间是可以来新的读者的。等读者全走完了,就将写信号量加一,这时可以写了
如果第一个来的是写者,那一开始就把WriteMutex置0了,想要读的时候还会触发P(WriteMutex),则读也读不了了
这种实现方法中,读者优先,一直有读者进来,写者就得一直等着
在读数据更频繁时这种策略更好
写者优先,则只要有写者就绪,后来的读者就必须阻塞,如果持续写入,则读者一直不能读
下面用管程来实现读者-写者问题
管程中维护四个状态变量,以及两个条件变量,一个锁
读者
写者