问题描述
有一个许多进程共享的数据区,这个数据区可以是一个文件或者主存的一块空间;有一些只读取这个数据区的进程(Reader)和一些只往数据区写数据的进程(Writer),此外还需要满足以下条件:
(1) 任意多个读进程可以同时读这个文件;
(2) 一次只有一个写进程可以往文件中写;
(3) 如果一个写进程正在进行操作,禁止任何读进程度文件。
读优先
一个读者试图进行读操作时,如果这时正有其他读者在进行操作,他可直接开始读操作,而不需要等待。
readcount //读者计数器
var rwmutex, rmutex = 1, 1;
int readcount = 0;
cobegin
procedure reader_i procedure Writer_j // i,j = 1,2,….
while true then while true then
begin begin
P(rmutex); P(rwmutex);
写更新;
Readcount + +; V(rwmutex);
if (readcount = = 1) end
P(rwmutex); // rwmutex 大于0时,自动从此处运行
V(rmutex);
读数据;
P(rmutex);
Readcount - -;
if (readcount = = 0)
V(rwmutex);
V(rmutex);
end
Coend
读优先–代码分析
读进程
- readcount 表示读进程数
- rmutex 是对于计数器readcount操作的互斥信号量,rwmutex表示是否允许写的信号量
- P(rmutex) 表示对每次有一个读者要进行读操作,要先对readcount 共享变量互斥操作,然后判断当前是否是第一名读者,如果是第一名读者,那么接下来将判断rwmutex信号量得出此时是否有作者在临界区(有的话,阻塞读进程;无,阻塞写进程)
- V(rmutex)表示结束对readcount共享信号量的互斥访问
- 读者读完后,又开始对readcount共享信号量的互斥访问,此时需要判断readcount是否为0,代表最后一个人离开读进程区,从而判断是否有写进程,if yes,唤醒其中一个写进程到临界区
写进程
- 如果有读进程,写进程阻塞
- 写进程完毕,判断是否有阻塞的读进程,if yes,唤醒其中一个读进程进入临界区。执行完V(rwmutex) 一方面相当于释放了写信号量,另一方面会自动唤醒读进程
写优先
1)多个读者可以同时进行读
2)写者必须互斥(只允许一个写操作,也不允许读写同时进行《rwmutex只有一份》)
3)写者优先于读者(一方面,一旦有写者(正在运行),则后续读者
必须等待,另一方面V(rwmutex)唤醒时 优先考虑写者,其次才是读者)
假设读者数是固定的
,算法如下:
rwmutex:用于写者与其他读者/写者互斥的访问共享数据
rmutex:该信号量初始值设为10,表示最多允许10个读者进程同时进行读操作
var rwmutex, rmutex: semaphore := 1, 10;
cobegin
procedure reader_i procedure Writer_j
begin begin // j = 1,2,….
P(rwmutex); P(rwmutex);
P(rmutex); for (i = 1;i <= 10;i + +) P(rmutex);
//读数据
V(rwmutex); //禁止新读者,并等待已进入的读者退出读进程
// 写更新;
V(rmutex); for (i = 1;i <= 10;i + +) V(rmutex);
end //恢复允许rmutex值为10,唤醒读进程
v(rwmutex)
end
Coend
写优先–代码分析
读进程
- 先检查P(rwmutex)确保:先有写操作时,读进程阻塞
- 先释放V(rwmutex) 一方面为了确保后续的读操作可以正常运行,另一方面此时如果有正在等待的写操作,优先唤醒写操作
- 读操作先运行就只有一种情况,就是必须在写操作之前申请rwmutex
写进程
- for (i = 1;i <= 10;i + +) P(rmutex); //一旦申请了写信号量,直接提前占用10个读信号量
- 写操作结束后,再通过循环释放读信号量