读者写者问题

Posted shaohsiung

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了读者写者问题相关的知识,希望对你有一定的参考价值。

1. 读者写者问题
读者优先: 只要有一个Reader处于活动状态, 那么后面来的Reader都会被接纳. 若Reader源源不断, 那么Writer就会一直处于阻塞状态, 即写者被饿死.

写者优先: 一旦Writer就绪, 就会先执行Writer, 写者优先级高于读者, 若Writer源源不断, 那么Reader就会一直处于阻塞状态, 即读者被饿死.

 

2. 信号量 - 读者优先

数据结构

1 data // 共享数据
2 CountMutex = 1 // 保证Rcount互斥
3 WriterMutex = 1 // 读者写者互斥
4 Rcount = 0 // 读者数量

 

写者

1 sem_wait(WriterMutex);
2 
3 write data;
4 
5 sem_post(WriterMutex);

 

读者

 1 sem_wait(Rcount);
 2 // 第一个读者进入, 获取共享区操作权限
 3 if (Rcount == 0) sem_wait(WriterMutex);
 4 ++Rcount;
 5 sem_post(Rcount);
 6 
 7 read data;
 8 
 9 sem_wait(Rcount);
10 --Rcount;
11 // 最后一个读者退出, 释放共享区操作权限
12 if (Rcount == 0) sem_post(WriterMutex);
13 sem_post(Rcount);

 

3. 管程 - 写者优先

数据结构

AR = 0 // 正在读的读者
AW = 0 // 正在写的写者
WR = 0 // 正在等待的读者
WW = 0 // 正在等待的写者
Condition okToRead // 条件变量: 可读
Condition okToWrite // 条件变量: 可写
Lock lock // 线程互斥锁

 

读者

 1 public Database::Read() {
 2     // wait until no writer
 3     StartRead();
 4 
 5     read database;
 6     
 7     // check out - wake up waiting writers
 8     DoneRead();
 9 }
10 
11 private Database::StartRead() {
12     lock.Acquire();
13     // 若存在正在写或正在等待的写者, 就将读者加入等待队列中
14     while ((AW + WW) > 0) {
15         WR++;
16         okToRead.wait(&lock); // 睡眠, 被唤醒后从这里开始执行
17         WR--;
18     }
19     // 允许同时存在多个读者
20     AR++;
21     lock.Release();
22 }
23 
24 private Database::DoneRead() {
25     lock.Acquire();
26     AR--;
27     // 若最后一个正在读的读者退出且有写者在排队, 那么就唤醒一个写者
28     if (AR == 0 && WW > 0) {
29         okToWrite.signal(); // 唤醒一个写者
30     }
31     lock.Release();
32 }

 

写者

 1 public Database::Write() {
 2     // wait until no readers or writers
 3     StartWrite();
 4 
 5     write database;
 6 
 7     // check out - wake up waiting writers or readers
 8     DoneWrite();
 9 }
10 
11 private Database::StartWrite() {
12     lock.Acquire();
13     // 若存在正在操作数据库的对象, 就等待
14     // 由于 AW 也包含, 所以一次只允许一个读者操作数据库
15     while ((AW + AR) > 0) {
16         WW++;
17         okToWrite.wait(&lock);
18         WW--
19     }
20     AW++;
21     lock.Release();
22 }
23 
24 private Database::DoneWrite() {
25     lock.Acquire();
26     AW--;
27     // 若存在正在等待的写者, 则唤醒随机一个
28     if (WW > 0) { // 条件1
29         okToWrite.signal();
30     }
31     // 若条件1不满足且存在正在等待的读者, 则唤醒全部正在等待的读者
32     else if (WR > 0) {
33         okToWrite.broadcast();
34     }
35     lock.Release();
36 }

 

以上是关于读者写者问题的主要内容,如果未能解决你的问题,请参考以下文章

Linux练习_线程练习_读者写者问题

读者写者问题,单例模式,自旋锁

用信号量和读写锁解决读者写者问题

多读者多写者

秒杀多线程第十一篇 读者写者问题

读者写者问题(读者优先 写者优先 读写公平)