问题描述
有读者,写者两组并发进程共享一个文件,如何才能让读者与读者之间,写者与写者之间互斥的对文件进行访问?
问题分析
- 读者与写者之间是互斥的.(如果在写文件的过程中进行读操作会导致"脏读")
- 读者与读者之间可以并发访问文件.(因为文件并不会被修改)
- 写者与写者之间需要互斥的访问文件.(多个文件同时写同一个文件的话会导致先前写入的数据被覆盖)
解决办法
- 设置rw信号量用于读写互斥.
- 设置count用来记录访问文件的读进程的数量.
//1.0 版本读者写者问题解决方案
semaphore rw;//用于读者写者之间互斥的访问文件
int count=0;//默认没有读者访问文件
//读者
Process writer(){
//进入区
p(rw);
//临界区
//-- 写文件
//剩余区
v(rw);
//退出区
}
//写者
Process reader(){
//进入区
if(count==0)
p(rw); //申请互斥锁
count++;
//临界区
// --读文件
//剩余区
count--; //表示自己已访问完文件
if(count==0)
v(rw);//释放互斥锁
//退出区
}
if(count==0)
p(rw); //申请互斥锁
count++;
......
count--; //表示自己已访问完文件
if(count==0)
v(rw);//释放互斥锁
以上代码存在一个很致命的问题:对count的检查和赋值并不是一气呵成的,这会导致可能多个读者进入if的判断语句,但是只有一个读者可以获得锁,其他读者会直接阻塞在这.
解决方案
//1.5 版本读者写者问题解决方案
semaphore rw;//用于读者写者之间互斥的访问文件
int count=0;//默认没有读者访问文件
semaphore rmutex //读者互斥锁,用于读者之间互斥的对count进行访问
//读者
Process writer(){
//进入区
p(rw);
//临界区
//-- 写文件
//剩余区
v(rw);
//退出区
}
//写者
Process reader(){
//进入区
p(rmutex);//确保同一时间只有一个读者可以进行对count的访问
if(count==0)
p(rw); //申请互斥锁
count++;
v(rmutex);
//临界区
// --读文件
//剩余区
p(count);
count--; //表示自己已访问完文件
if(count==0)
v(rw);//释放互斥锁
v(count);
//退出区
}
以上解决方案已经很完善了,但仍然存在一个问题:count的值大部分情况下都是大于1的,而只有所有的读者访问完文件之后最后一个读者才会释放读写互斥锁,很可能导致写者会因此饿死.
读写公平法
再添加一个信号量v,确保当写者想使用文件时,在那之后申请访问文件的读者会暂时阻塞直到写者完成任务.
//2.0 读者写者问题解决方案
semaphore s;//用来平衡读者写者之间的优先级
semaphore rw;//用于读者写者之间互斥的访问文件
int count=0;//默认没有读者访问文件
semaphore rmutex //读者互斥锁,用于读者之间互斥的对count进行访问
//读者
Process writer(){
//进入区
p(s);
p(rw);
//临界区
//-- 写文件
//剩余区
v(rw);
v(s);
//退出区
}
//写者
Process reader(){
//进入区
p(s);
p(rmutex);//确保同一时间只有一个读者可以进行对count的访问
if(count==0)
p(rw); //申请互斥锁
count++;
v(rmutex);
v(s);
//临界区
// --读文件
//剩余区
p(count);
count--; //表示自己已访问完文件
if(count==0)
v(rw);//释放互斥锁
v(count);
//退出区
}
当写者提出要访问文件时,之后的读者都会等待写者释放s锁,所以当之前开始的读者完成任务时就会轮到写者进行作业.