2.3.9 读者-写者问题
知识来源: B站王道考研
允许多个读者可以同时对文件执行读操作
只允许一个写者往文件中写信息
任一写者在完成写操作之前不允许其他读者或写者工作
写者执行写操作之前,应已有读者和写者全部退出。
问题分析
- 关系分析。找到各个进程,分析它们之间的同步、互斥关系。
- 整理思路。根据各进程的操作流程确定P、V操作的大致顺序。
- 设置信号量。设置需要的信号量,并根据题目条件确定信号量初值。
两类进程:写进程、读进程。
互斥关系:写写互斥,读写互斥。
写进程与其他进程互斥所以定义一个rw互斥信号量。
初步代码:
// 用于实现对文件的互斥访问。表示当前是否有进程在访问进程文件。
semaphore rw = 1;
int count = 0; // 记录当前有几个读进程在访问
semaphore mutex = 1;
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 --; // 记录访问文件读线程数量 - 1
if(count == 0) V(rw); // 最后一个解锁
V(mutex);
}
}
潜在问题:只要有读进程还在读,写进程就要一直阻塞,可能“饿死”。因此,该算法为读进程优先。
读写公平:
// 用于实现对文件的互斥访问。表示当前是否有进程在访问进程文件。
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 --; // 记录访问文件读线程数量 - 1
if(count == 0) V(rw); // 最后一个解锁
V(mutex);
}
}
核心思想: 设置了一个计数器count 用来记录当前正在访问共享文件的读进程数。