管程实现读者优先and写者优先
前提条件
- 允许多个读者可以同时对文件执行读操作;
- 只允许一个写者往文件中写信息;
- 任一写者在完成写操作之前不允许其他读者或写者工作;
信号量的实现
1 | class Semaphore{ |
《读者优先》读者可以插队
semaphore rw = 1;
实现读、写进程对文件的互斥访问semaphore mutex = 1;
实现互斥修改变量int readcnt = 0;
记录当前有几个读者在读
写者进程
1 | while(true): |
读者进程
1 | while(true): |
分析:
第一个读者进程 就锁住了 之后所有的写操作,直到最后一个读者进程执行完毕才释放这个锁rw,此时才能进行写的操作。
《读写公平》
semaphore rw = 1; 实现读、写进程对文件的互斥访问
semaphore w = 1; 实现写进程之间对文件的互斥访问
semaphore mutex1 = 1, mutex2 = 1; 实现互斥修改变量
int readcnt = 0, writecnt = 0; 分别记录当前有几个读、写进程想访问临界区
写者进程
1 | while(true): |
读者进程
1 | while(true): |
分析:
当写者拿到rw锁时,后来的写者都可以直接等待在P(w)处(在临界区外排队等待进入),而后来的读者中有一个会阻塞在P(rw),剩余的阻塞在P(mutex2),这样一来读者也需要等待多个写者了,而方案二中读者最多只需要等一个写者。
这时的情况像是读、写进程是两个派别,谁先第一个拿到rw锁,其派别的 “兄弟们” 都能跟着他一起上。没拿到锁的一方只能等对方所有人完成后才能执行。
因此有多个读者访问临界区时,写者也只能等待,而我们希望的是写者能够抢占读者进程,不需要等后来的读者。所以这种方案也只能说是再一步提高了写进程的优先级。
《写者优先》写者可以插队
思路:
在保证写者互斥、读写互斥、可多个读者同时执行的前提下,额外加一个变量记录执行中写者的数量,再加一个信号量实现只要【读读写写读读读写写读】中有写者还没执行完,读者就要等待。
semaphore rw = 1; 实现对文件的互斥访问
semaphore mutex = 1, mutex1 = 1, mutex2 = 1; 实现互斥修改变量
semaphore mutex3 = 1; 保证只有一个写者,读者进程会被卡在 P( read )
semaphore read = 0; 同步锁:读进程必须在没有写进程时才能访问临界区
int readcnt = 0, writecnt = 0; 分别记录当前有几个读进程在读、有几个写进程想写
bool waiting = false; 表示当有写进程在写文件时,有没有读进程来到
写者进程
1 | while(true): |
读者进行
1 | while(true): |
分析:
读者1 → 写者 → 读者2:假设读者1占有rw资源,写者来到阻塞在P(rw)处,此时 writecnt已经不是 0。所以读者2 再来时会被阻塞在P(read)处。当读者1 完成读操作释放rw锁,然后写者立即会占有rw,此时一直有写者来的话都是可以直接在临界区外排队的。等所有写操作完成了,writecnt 就变为 0,读者才能获得read锁进行读。
在读者先于写者来到的情况下,写者总是会获得rw锁,因为当有写者在等待rw时,其它后来的读者中的第一个会阻塞在P(read),剩余的阻塞在P(mutex3)。而前面已经在临界区的读者,写完后就会有readcnt==0然后释放rw锁,写者立刻就可以访问临界区了。但是在上一个方案的话,因为后来的读者不会进行 “检查”,只要它们中有一个读者持有rw锁,即使已经有写者正在等待,读者们依然可以直接进入临界区,但在本方案中却会被阻塞在P(mutex3)或P(read)。
1 | //(自己重写一下) |
参考原文:https://blog.csdn.net/qq_43280818/article/details/105788767