操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)

前篇在此:
操作系统清华向勇陈渝版笔记(九) 同步协同多道程序设计和并发问题,同步互斥,死锁,临界区
操作系统(八)CPU调度 短剩余时间 吞吐量 轮循 实时调度 多处理器调度 (清华 向勇 陈渝版)

index
10-1 信号量
10-2 如何使用信号量
10-3 信号量实现细节
10-4 管程 条件变量
10-5 经典同步问题

10-1 信号量 Semaphore

操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第1张图片

一个整型int(sem),可进行两个原子操作

P() sem–,如果sem<0,等待,否则继续,类似lock_acquire
V() sem++,如果sem<=0,说明当前有等着的,唤醒挂在信号量上的进程,可以是一个,可以是多个

Dijkstra在20实际60年代提出,P,V都是荷兰语,在早期操作系统中,P,V是主要的同步原语。

类似信号灯
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第2张图片

特征
信号量是整数,有符号,一般初始是>0的数,一旦小于0就不能继续,要挂在信号量上,其他进程做V操作才能唤醒,具体唤醒哪个取决于具体的算法,如常用FIFO先来先服务,较为公平;
信号量是被保护的变量,初始化完成后只能通过P() V()这两个原子操作改变值,P操作会阻塞,V不会

思考:spinlock能否是FIFO?

10-2 如何使用信号量

两种类型:
二进制信号量:约等于锁,取值0 or 1
general counting一般/技术信号量:任何非负值
可以用在两个方面,互斥或者条件同步(调度约束—–一个线程等待另一个线程的事情发生)

用二进制信号量实现锁的互斥

mutex= new semaphore(0)
mutex->P();
…Critical section…
mutex->V();

实现调度约束

condition=new semaphore(0);
for thread A   condition->P(); 开始等待
for thread B   condition->V(); 发出信号唤醒A ,B在V操作之前的语句执行完后才能执行A的P之后的语句----同步

条件同步
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第3张图片

正确性要求:可以多个生产者访问Buffer写数据,但写的时候消费者不能有操作(互斥),缓冲区空,消费者必须等待生产者,缓冲区满,生产者必须等待消费者(调度/同步约束)。

每个约束用一个单独的信号量,设置三个
二进制信号量互斥(1/0),一般信号量fullbuffers,一般信号量emptybuffer

初始化

Class BoundedBuffer{
Mutex = new semaphore(1);
fullBuffers = new semaphore(0);
emptyBuffers = new semaphore(n); //当前生产者可以往里面放多少个数据
}

如果Buffer不空,则full/empty设别的值

BoundedBuffer::Deposit(c){
emptyBuffer->P();           //n个生产者都可以进入直到empty<0被阻塞,不能先锁再emptybuffer--, 不然会在Buffers满的时候死锁
mutex->P(); Add c to the buffer; mutex->V();
fullBuffers->V();               //初始是0,只有先V()不然消费者不能取}
BoundedBuffer::Remove(c){ 
fullBuffers->P();           //  初始是0时会被挂起
mutex->P();Remove c from buffer; mutex->V();
emptyBuffers->V();
}
P&V可以换顺序吗?可以。

10-3 信号量实现细节

class Semaphore{
int sem;
Waitqueue q;}

Semaphore::P(){
sem--;
if(sem<0){Add this thread t to q;   block(p);}
}

Semaphore::V(){
Sem++;
If(sem<=0){
Remove a thread t from q;   wakeup(t);}
}

存在问题:

  • 信号量的双用途,互斥和条件同步,等待条件是独立的互斥。和LOCK有区别,LOCK是通过忙等/等待队列实现sleep,信号量是等待队列。
  • 开发容易犯错,比较困难
  • 不能够处理死锁

10-4 管程 条件变量

管程monitor 包含了一系列的共享变量,以及针对这些变量的操作的函数的组合/模块
包含了:一个锁,指定临界区,确保互斥性;0或者多个条件变量,根据条件的个数决定,等待/通知信号量,并发访问共享数据
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第4张图片

lock acquire & release 可以写函数也可以是语言级的

condition variable 条件变量

wait() 释放锁,睡眠

signal / broadcast 唤醒等待者

类似信号量 要维持每一个条件队列
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第5张图片
num waiting与信号量有差异,是等的队列的数目;signal不一定会使其减一


操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第6张图片
调用管程解决消费者生产者问题
count记录了当前BUFFER的数据个数
先在前后加锁,因为要保证只有一个线程在临界区 lock在等待/睡眠的时候通过notfull.wait(&lock)释放锁。唤醒后获得锁。


执行signal后,管程中有两个线程可以执行,应该选择哪个呢?
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第7张图片

操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第8张图片
While和if的区别,前者release后是挂在条件变量上的多个线程抢CPU,抢到谁给谁,所以要check again, 后者是直接转交给了下一个线程,始终满足count< n的条件,所以直接走IF下面的语句

临界区和MONITOR比较:

操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第9张图片

  • 两个同步互斥的机制,临界区和monitor,比起LOCK都可以解决更广泛的问题,但也都离不开底层的硬件支持。
  • 同步互斥的不确定性强,调试困难。

同步结构

  • 锁:互斥
  • 条件变量:有条件的同步
  • 其他原语:信号量

10-5 经典同步问题

读者-写者问题
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第10张图片
读者只读,写者可以读取和写入。
读者优先,不按时间顺序,跳过等待的写者优先进行读操作。

信号量的实现:
Data是共享变量
整数Rcount 当前读者的数目初始化为0,当前写者只有一个
保证互斥 信号量countmutex读者 writemutex写者 初始化为1
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第11张图片
writemutex操作保证了写的互斥,和当前没有读者时,读者进入的互斥。
Rcount保证了可以有多个读者,由于自身是共享变量(对多个读者而言),所以在++ /– /判断操作的前后要用到countmutex

利用管程实现读者写者问题:
写者优先
存在两类写者,正在操作的写者和在等待的,只有两类都不存在时读者才可以进入
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第12张图片
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第13张图片

哲学家就餐问题
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第14张图片
用信号量解决
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第15张图片

改进,如果右边叉子在,就吃,不然就等

if(fork((i+1)%N)){take_fork((i+1)%N);   break;}
else{put_fork(i);   wait_some/random_time();}

如果都等待的是相同的时间,5个人同步,那肯定更不行
如果是随机时间,可行。但不完美。可能会饥饿。

操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第16张图片
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第17张图片
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第18张图片

#define N 5
#define Left ((n+i-1)%n)
#define Right ((n+i+1)%n)

操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第19张图片
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第20张图片
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第21张图片
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第22张图片
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)_第23张图片

eating其实就是临界区
think 开始要置为thinking 且state是临界资源,要用P,V来保护
先用人脑子想伪代码,再想变量和特殊数据结构的变量,互斥还是同步?逐步细化。注意match
避免死锁,饥饿,低效。

后一篇:
操作系统清华大学版笔记(十一)死锁、死锁预防、死锁避免、死锁恢复、银行家算法和进程间通信(直接通信、间接通信)

你可能感兴趣的:(操作系统)