目录
1. 问题描述
读写文件的规则:
- 允许多个进程同时读一个共享对象
- 不允许一个写进程和其它读进程或写进程同时访问共享对象
读者-写者问题:是指保证一个写进程必须与其它进程互斥地访问共享对象的同步问题。
2. 问题分析
1)由于不允许一个写进程和其它读进程或写进程同时访问文件,因此需要设置一个互斥型信号量 wmutex 来控制文件的使用权。
2)由于只要有一个读进程在读就不允许写进程去写,因此我们需要设置一个整型变量 readcount 来记录正在读的进程数目。仅当 readcount = 0 时,才允许写进程去写。
- 第一个读进程负责取得文件的使用权(此时 readcount = 0)
- 最后一个读进程负责释放文件的使用权(此时 readcount = 0)
3)一旦一个读进程进去了,该进程就要做 readcount + 1 操作;一旦一个读进程要出去,该进程就要做 readcount - 1 操作。
4)由于 readcount 是一个可被多个读进程访问的临界资源,因此需要设置一个互斥型信号量 rmutex 。
3. 利用记录型信号量解决读者-写者问题
读者进程描述如下:
void reader() {
do {
wait(rmutex);
//第一个读进程负责取得文件的使用权
if(readcount == 0) wait(wmutex);
//其余读进程只用负责计数
readcount = readcount + 1;
signal(rmutex);
//perform read operation
wait(rmutex);
readcount = readcount - 1;
//最后一个读进程负责释放文件的使用权
if(readcount == 0) signal(wmutex);
signal(rmutex);
} while(true);
}
写进程描述如下:
void writer() {
do {
wait(wmutex);
//perform write operation
signal(wmutex);
} while(true);
}
4. 利用信号量集解决读者-写者问题
该方法增加了一个限制,即最多只允许 RN 个读进程同时读。
记录型信号量方法是用加一的方式来记录读进程的数量,而信号集方法是用减一的方式来记录读进程的数量,同时也对读进程数量形成了限制。
1)由于允许多个进程同时读一个共享对象,因此设置一个资源型信号量 L,其初始值为 RN 。
int RN;
semaphore L, mx;
L.value = RN;
mx.value = 1;
每进入一个读进程,则 L - 1;当 L 减为 0 时,不再允许读进程进入。
Swait(L, 1, 1);
2)由于不允许一个写进程和其它读进程或写进程同时访问文件,因此需要设置一个互斥型信号量 mx 来控制文件的使用权。
对于写进程有:
Swait(mx, 1, 1, L, RN, 0);
Swait 操作就是一个升级版的 AND 信号量机制,只有当:
- mx >= 1,即文件的使用权尚在
- L >= RN,即没有读进程在读文件
时,写进程才能去写文件。
对于读进程有:
Swait(mx, 1, 0);
只有当 mx >= 1,即文件的使用权尚在时,读进程才能去读文件。这里的 Swait 相当于一个可控开关,它不修改信号量 mx,只是起到判断的作用。
由于只能有一个写进程,因此该写进程必须要修改信号量 mx;由于允许有多个读进程,因此每个读进程不能修改信号量 mx,否则后面的读进程无法进入。
读进程描述如下:
void reader() {
do {
Swait(L, 1, 1);
Swait(mx, 1, 0);
//perform read operation
Ssignal(L, 1);
} while(true);
}
写进程描述如下:
void writer() {
do {
Swait(mx, 1, 1, L, RN, 0);
//perform write operation
Ssignal(mx, 1);
} while(true);
}
信号量集机制设置下限的一个原因:虽然我一个资源也不申请,但是你必须得有这么多个资源。