问题描述
使用信号量进行解决
优先策略选择
读者优先
semaphore ReaderWriterMutex = 1; //实现读写互斥
int Rcount = 0; //读者数量
semaphore CountMutex = 1; //读者修改计数互斥
writer(){
while(true){
P(ReaderWriterMutex);
write;
V(ReaderWriterMutex);
}
}
reader(){
while(true){
P(CountMutex);
if(Rcount == 0) //当第一个读者进来时,阻塞写者
P(ReaderWriterMutex);
++Rcount;
V(CountMutex);
read;
P(CountMutex);
--Rcount;
if(Rcount == 0)
V(ReaderWriterMutex); //当最后一个读者离开后,释放写者
V(CountMutex);
}
}
上述方案为读者优先。因为当读者进行读取的时候,如果后面一直有读者进入,那么写者就会被阻塞,直到所有读者完成之后,写者才可以进行。
写者优先
semaphore ReaderWriterMutex = 1; //实现读写互斥
int Rcount = 0; //读者数量
semaphore CountMutex = 1; //读者修改计数互斥
semaphore WriterMutex = 1; //用于实现写者优先
writer(){
while(true){
P(WriterMutex); //无写进程时进入
P(ReaderWriterMutex); //互斥访问共享文件
write;
V(ReaderWriterMutex); //释放共享文件
V(WriterMutex); //恢复对共享文件的访问
}
}
reader(){
while(true){
P(WriterMutex); //无写进程时进入
P(CountMutex);
if(Rcount == 0) //当第一个读者进来时,阻塞写者
P(ReaderWriterMutex);
++Rcount;
V(CountMutex);
V(WriterMutex);//恢复对共享文件的访问
read;
P(CountMutex);
--Rcount;
if(Rcount == 0)
V(ReaderWriterMutex); //当最后一个读者离开后,释放写者
V(CountMutex);
}
}
上述方案为写者优先。设置一个WriterMutex信号量来实现优先读。我们可以看到,当有写者进入时,通过P(WriterMutex)阻塞了读者。
使用管程方法
int AR = 0; //表示正在读的读者
int AW = 0; //表示正在写的写者
int WR = 0; //表示正在等待的读者
int WW = 0; //表示正在等待的写者
Lock lock;
Condition okToRead; //可以读取
Condition okToWrite; //可以写入
Database::Read(){
//Wait until no writers;
StartRead();
read database;
//check out - wake up waiting writers;
DoneRead();
}
Database::StartRead(){
lock.Acquire();
//当存在写者,则阻塞读者
while((AW + WW) > 0){
WR ++;
okToRead.Wait(&lock);
WR --;
}
//读者进行读
AR++;
lock.Release();
}
Database::DoneRead(){
lock.Acquire();
//读者完成读
AR --;
//当正在读的读者都完成后,唤醒写者
if(AR == 0 && WW > 0){
okToWrite.signal();
}
lock.Release();
}
Database::Writer(){
//Wait until no readers/writers;
StartWrite();
writer database;
//check out - wake up waiting readers/writers;
DoneWrite();
}
Database::StartWrite(){
lock.Acquire();
//若存在正在读的读者或正在等待的写者,则阻塞当前写者
while((AR + AW) > 0){
WW ++;
okToWrite.Wait(&lock);
WW --;
}
//进行写
AW++
lock.Release();
}
Database::DoneWrite(){
lock.Acquire();
//写完成
AW --;
//写者优先,若存在等待的写者,先唤醒等待的写者
if(WW > 0){
okToWrite.signal();
} else if (WR > 0){
okToRead.signal();
}
lock.Release();
}