代码仓库:JJLi0427/operationsystem (github.com)
1.问题描述:
有一个文件,可以有多个读者同时读取,但是只能有一个写者进行写操作,读者和写者对文件的访问是互斥的。这个理我们要提高写者的优先级,使得处理机可以让写者更优先操作文件
2.解决思路:
这个问题的提出是为了解决普通读者写者问题的方案造成的写者饥饿问题。
之前我也做过读者优先的方案可以参考这个博客读者优先的读者写者问题程序解决_哆啦叮当的博客-CSDN博客
首先设计一个文件读写的临界资源访问量rw,使得读者和写者可依互斥操作文件。然后因为有多个读者可以同时查看文件,所以我们可以设置一个rcount来记录读者数量。rcount变量为0时要对rw做p/v操作。但是我们为了不发生读者同时操作rcount,还需要增加一个互斥信号量rmutex。为了保证写者的优先,我们还需要设置一个写者优先信号量use,这个信号量在读者中优先级高于rcount,所以可以使得写者优先获得文件的操作,但是因为写者可能有多个人,而且他们不能同时访问同一个文件。所以还需要设计一个写者计数信号量wcount,并且配套设计一个wmutex实现wcount信号量互斥访问。当wcount为0时,就需要对use操作,当对use进行了v操作之后,读者进程就会被阻塞,直到没有写者需要操作文件。这样做程序也就实现了写者优先。
3.程序实现:
c++实现如下,编译时需加上 -lpthread
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
using namespace std;
sem_t rw, rmutex, wmutex, use; //rw访问文件信号量,rmutex/wmutex是实现rcount/wcount互斥访问信号量,use是写者优先的信号量
int rcount = 0, wcount = 0; //分别记录读者和写者数量
typedef struct ThreadData {
int id;
int setup;
int exe;
} tdata; //线程的数据结构
void* reader(void* p) {
int id = ((tdata*)p)->id;
int setup = ((tdata*)p)->setup;
int exe = ((tdata*)p)->exe;
sleep(setup);
printf("thread %d: wait to read\n", id);
sem_wait(&use); //等待写者优先信号量
sem_wait(&rmutex); //实现rcount互斥访问
if(rcount == 0)
sem_wait(&rw); //rcount为0时操作使用文件信号
rcount++;
sem_post(&rmutex);
sem_post(&use);
printf("thread %d: start reading\n", id);
sleep(exe);
printf("thread %d: end reading\n", id);
sem_wait(&rmutex);
rcount--;
if(rcount == 0)
sem_post(&rw);
sem_post(&rmutex);
pthread_exit(0);
return NULL;
}
void* writer(void* p) {
int id = ((tdata*)p)->id;
int setup = ((tdata*)p)->setup;
int exe = ((tdata*)p)->exe;
sleep(setup);
printf("thread %d: wait to write\n", id);
sem_wait(&wmutex); //实现wcount互斥访问
if(wcount == 0)
sem_wait(&use); //写者优先
wcount++;
sem_post(&wmutex);
sem_wait(&rw); //实现读者和写者对文件互斥访问
printf("thread %d: start writing\n", id);
sleep(exe);
printf("thread %d: end writing\n", id);
sem_post(&rw);
sem_wait(&wmutex);
wcount--;
if(wcount == 0)
sem_post(&use);
sem_post(&wmutex);
pthread_exit(0);
return NULL;
}
int main() {
int num = 5; //设置读者和写者的人数
pthread_t tid[num]; //线程号初始化
pthread_attr_t attr;
pthread_attr_init(&attr); //线程属性初始化
sem_init(&rmutex, 0, 1);
sem_init(&wmutex, 0, 1);
sem_init(&rw, 0, 1);
sem_init(&use, 0, 1);
char worklist[num] = "rwrrw";
int setuplist[num] = {2, 3, 1, 5, 1};
int exelist[num] = {1, 5, 2, 3, 1}; //设置不同的读者和写者的等待时间和执行时间
for(int id = 0; id < num; id++) {
tdata* d = new tdata;
d->id = id;
d->setup = setuplist[id];
d->exe = exelist[id];
if(worklist[id] == 'r') {
printf("create thread %d: reader\n", id);
pthread_create(&tid[id], &attr, reader, d); //创建读者线程
}
else if(worklist[id] == 'w') {
printf("create thread %d: writer\n", id);
pthread_create(&tid[id], &attr, writer, d); //创建写者线程
}
}
for(int i = 0; i < num; i++) {
pthread_join(tid[i], NULL); //等待所有线程结束
}
sem_destroy(&rmutex); //销毁信号量
sem_destroy(&wmutex);
sem_destroy(&rw);
sem_destroy(&use);
return 0;
}
4.运行结果:
create thread 0: reader
create thread 1: writer
create thread 2: reader
create thread 3: reader
create thread 4: writer
thread 2: wait to read
thread 4: wait to write
thread 4: start writing
thread 2: start reading
thread 0: wait to read
thread 0: start reading
thread 4: end writing
thread 1: wait to write
thread 0: end reading
thread 1: start writing
thread 2: end reading
thread 3: wait to read
thread 3: start reading
thread 3: end reading
thread 1: end writing