操作系统实验——读者写者模型(写优先)
个人博客主页
参考资料:
Java实现PV操作 | 生产者与消费者
读者写者
对一个公共数据进行写入和读取操作,和之前的生产者消费者模型很类似,我们梳理一下两者的区别。
- 都是多个线程对同一块数据进行操作
- 生产者与生产者之间互斥、消费者与消费者之间互斥、生产者与消费者之间互斥
- 写者与写者之间互斥、读者与写者之间互斥、但读者与读者之间并发进行
写优先是说当有读者进行读操作时,此时有写者申请写操作,只有等到所有正在读的进程结束后立即开始写进程
定义PV操作
/**
* 封装的PV操作类
* @count 信号量
*/
class syn{
int count = 0;
syn(){
}
syn(int a){
count = a;}
//P操作
public synchronized void Wait() {
count--;
if(count < 0) {
//block
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//V操作
public synchronized void Signal() {
count++;
if(count <= 0) {
//wakeup
notify();
}
}
}
全局信号量
全局信号量中用到了三个信号量w、rw、mutex,初始化都等于1。下面一一做解释。
- 先从最简单的mutex说,mutex用来互斥访问count变量,对读者数目的加加减减。
- 然后是rw,当第一个读进程进行读操作时候,会持有rw锁而不释放,在它读的过程中如果有写进程想要写数据,就无法在此时进行写操作,此时可能还会进来多个读进程,而只有当最后一个读进程执行完读操作的时候才会将rw锁释放。从而保证了如果在有一个或多个读者正在进行读操作时,写进程试图写数据,只能等到所有正在读的进程读完才行。
- 最后是w锁,也是最复杂的一个,作用有二:
- 保证了写者与写者之间的互斥,这个是很简单的
- 保证了写优先的操作,是必要而不充分条件。如果此时有三个读进程正在进行读操作,而此时有一个写进程进入试图进行写操作,由于第一个读者进入时持有了rw锁,而导致写者在持有w锁后(读者进程虽然刚开始也会持有w锁,但都是很快又释放的,所以不影响写进程获取w锁资源)被wait在rw锁那块,其实执行的wait方法是
rw.wait()
,而它本身还是持有w锁的,也就是说之后如果还有读/写进程试图进行读操作时,就会在刚开始因为无法获取w锁资源而被wait,执行的wait语句是w.wait()
,因为w锁被写进程持有,所以在写进程写完之前都不会释放,当最后一个读者读完后,执行notify方法,其实是对rw锁的释放rw.notify()
,此时也只有那个等待的写者进程可以被唤醒,从而实现了写优先的操作。
class Global{
static syn w = new syn(1); //让写进程与其他进程互斥
static syn rw = new syn