问题描述:有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:
①允许多个读者可以同时对文件执行读操作;
②只允许一个写者往文件中写信息;
③任一写者在完成写操作之前不允许其他读者或写者工作;
④写者执行写操作前,应让已有的读者和写者全部退出。
问题分析:
两类进程:写进程、读进程
互斥关系:写进程—写进程、写进程—读进程。读进程与读进程不存在互斥问题。
读进程优先算法
/***********信号量定义*************/
semaphore rw=1; //用于实现对共享文件的互斥访问
int count = 0; //记录当前有几个读进程在访问文件
semaphore mutex = 1;//用于保证对count变量的互斥访问
/**********************************/
/**********写者进程*************/
writer (){
while(1){
P(rw); //写之前“加锁”
写文件操作…
V(rw); //写完了“解锁”
}
}
/**********************************/
/***************读者进程**************/
reader (){
while(1){
P(mutex); //各读进程互斥访问count
if(count==0) //由第一个读进程负责
P(rw); //读之前“加锁”
count++; //访问文件的读进程数+1
V(mutex);
读文件…
P(mutex); //各读进程互斥访问count
count--; //访问文件的读进程数-1
if(count==0) //由最后一个读进程负责
V(rw); //读完了“解锁”
V(mutex);
}
}
/********************************/
以上就是读进程的优先的代码演示。
问题一:为啥要设置metex这个互斥信号量呢?我们先假设一下没用这个信号量时的情况。代码如下:
reader (){
while(1){
if(count==0) //由第一个读进程负责
P(rw); //读之前“加锁”
count++; //访问文件的读进程数+1
读文件…
count--; //访问文件的读进程数-1
if(count==0) //由最后一个读进程负责
V(rw); //读完了“解锁”
}
}
我们假设这个时候两个写者进程同时进入。都执行了第三行代码if(count==0)判断到count为0,都进入P(rw)的加锁操作。此时必然有一个进程阻塞在此。所以加上metex这个互斥信号量来保证各读进程互斥访问count。那么有人问了我用count++来让对count的操作都在一条代码中是否可行。
// An highlighted block
if(count++ == 0) //count++和判断同时执行
P(rw); //读之前“加锁”
//count++; //已合并到第一行代码中
这样做当然是不可行的,因为 count++不属于原子操作,它的执行过程为1、读内存到寄存器i2、在寄存器中自增;3、写回内存。所以只能通过加锁来实现。
问题二:当源源不断的有读者进程进入时,就永远执行到不最后一个读进程解锁的代码,此时写进程就只能一直在等待这就造成了“饥饿”的现象。所以这种写法被称为读者优先。为了解决这个问题我们又引出了写者优先的解决算法。
写者优先算法
/***********信号量定义*************/
semaphore rw=1; //用于实现对共享文件的互斥访问
int count = 0; //记录当前有几个读进程在访问文件
semaphore mutex = 1;//用于保证对count变量的互斥访问
semaphore w=1; //用于实现写优先
/**********************************/
/**********写者进程*************/
writer (){
while(1){
P(w);
P(rw);
写文件…
V(rw);
V(w);
}
}
/**********************************/
/***************读者进程**************/
reader (){
while(1){
P(w);
P(mutex); //各读进程互斥访问count
if(count==0) //由第一个读进程负责
P(rw); //读之前“加锁”
count++; //访问文件的读进程数+1
V(mutex);
V(w);
读文件…
P(mutex); //各读进程互斥访问count
count--; //访问文件的读进程数-1
if(count==0) //由最后一个读进程负责
V(rw); //读完了“解锁”
V(mutex);
}
}
/********************************/
在写优先算法中,哪怕有源源不断的读进程进入时都不会饿死写进程。因为当未v(w)时都会在p(w)中被挂起,而当v(w)时谁先进入的挂起队列谁优先。这属于先来先服务原则,又叫读写公平法。
参考于2019 王道考研 操作系统课程。