经典同步问题 读者-写者问题
读者-写者问题
在读者-写者问题中,只对共享数据进行读取的进程为读者进程,修改共享数据的进程称为写者进程。多个读者可同时读取共享数据而不会导致出现错误,但是任何时刻多个写者进程不能同时修改数据,写者进程和读者进程也不能同时访问共享数据。读者-写者问题的解决策略有不同的倾向。
读者优先
需要用到的共享变量:
semaphore rw_mutex = 1; // 读者与写者互斥访问共享数据的互斥信号量
semaphore mutex = 1; // 多个读者进程互斥修改当前读者进程数量的信号量
int read_count = 0; // 系统当前读者进程数量
写者进程结构
do {
wait(rw_mutex);
...
/* 修改共享数据 */
...
signal(rw_mutex);
}while(true);
读者进程结构
do {
wait(mutex); // 获取修改读者进程数量的互斥信号量,该操作在请求rw_mutex之前,防止出现死锁
read_count++;
if(read_count == 1) // 判断当前是否为第一个读者进程
wait(rw_mutex); // 如果是就需要请求访问共享数据的互斥信号量
signal(mutex); // read_count修改后释放信号量
...
/* 读取数据 */
...
wait(mutex); // 获取修改读者进程数量的互斥信号量
read_count--;
if(read_count == 0) // 判断当前进程是否为最后一个读者进程
signal(rw_mutex); // 如果是则释放共享数据的互斥信号量,以允许写者进程操作共享数据
signal(mutex);
}while(true);
读者优先有可能导致写者进程产生饥饿现象,当系统中不断出现读者进程时,写者进程始终无法进入临界区。
写者优先
需要用到的共享变量:
semaphore rw_mutex = 1; // 读者与写者互斥访问共享数据的互斥信号量
semaphore r_mutex = 1; // 互斥修改当前读取文件的进程数
semaphore w_mutex = 1; // 互斥修改当前修改文件的进程数
semaphore enter_mutex = 1; // 获取申请访问文件的权限
int read_count = 0; // 系统当前读者进程数量
int write_count = 0; // 系统当前写者进程数量
写者进程结构
do {
wait(w_mutex); // 新的写者进程进入,获取修改写者进程数量的权限
write_count++;
if(write_count == 1) // 判断当前是否为第一个写者进程
wait(enter_mutex); // 阻断后续到达的读者进程
signal(w_mutex);
wait(rw_mutex); // 获取访问文件的权限,文件可能被其它写者进程占用,或者等待最后一个读者进程释放
...
/* 修改数据 */
...
wait(rw_mutex);
wait(w_mutex);
write_count--;
if(write_count == 0) // 当所有写者进程都放弃使用文件时,运行读者进程申请访问文件
signal(enter_mutex);
signal(mutex);
}while(true);
读者进程结构
do {
wait(enter_mutex); // 获取申请访问文件的权限
wait(r_mutex);
read_count++;
if(read_count == 1) // 判断当前是否为第一个读者进程
wait(rw_mutex); // 占用文件
signal(r_mutex);
signal(enter_mutex);
...
/* 读取数据 */
...
wait(r_mutex);
read_count--;
if(read_count == 0)
signal(rw_mutex);
signal(r_mutex);
}while(true);
写者优先有可能导致读者进程产生饥饿现象,当系统中不断出现写者进程时,读者进程始终无法进入临界区。
读写公平
需要用到的共享变量:
semaphore rw_mutex = 1; // 读者与写者互斥访问共享数据的互斥信号量
semaphore r_mutex = 1; // 互斥修改当前读取文件的进程数
semaphore enter_mutex = 1; // 获取申请访问文件的权限
int read_count = 0; // 系统当前读者进程数量
写者进程结构
do {
wait(enter_mutex); // 阻断后续到达的读者进程
wait(rw_mutex);
...
/* 修改数据 */
...
signal(rw_mutex);
signal(enter_mutex);
}while(true);
读者进程结构
do {
wait(enter_mutex); // 获取申请访问的权限,这里与写者优先的区别在于,写者放弃占用文件时,所有读者 都可以与写者进程进行再次竞争
wait(r_mutex);
read_count++;
if(read_count == 1) // 判断当前是否为第一个读者进程
wait(rw_mutex);
signal(r_mutex);
signal(enter_mutex); // 释放许可,其余读者和写者进程将进行下一轮竞争
...
/* 读取数据 */
...
wait(r_mutex);
read_count--;
if(read_count == 0)
signal(rw_mutex);
signal(r_mutex);
}while(true);