欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-20 11:53:05
...

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

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

10-1 信号量 Semaphore

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

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

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

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

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

特征
信号量是整数,有符号,一般初始是>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之后的语句----同步

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

正确性要求:可以多个生产者访问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或者多个条件变量,根据条件的个数决定,等待/通知信号量,并发访问共享数据
操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)

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

condition variable 条件变量

wait() 释放锁,睡眠

signal / broadcast 唤醒等待者

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


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


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

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

临界区和MONITOR比较:

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

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

同步结构

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

10-5 经典同步问题

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

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

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

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

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

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

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

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

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

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

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

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