这是这学期操作系统课的第一次实验:分别实现读者优先和写者优先的读者写者问题。
这次的实验都基于Ubuntu系统通过C语言实现。本实验参考了这篇文章。
读者优先和写者优先的唯一区别是:
其他读者正在读,且有写者等待时,新读者到来后
(1)读者优先:可读
(2)写者优先:等待
下面是代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <getopt.h>
#define N_READER 10
#define N_WRITER 5
/*
* 测试文件格式为:
* R 进程ID 持续时间
* W 进程ID 持续时间 写入数据
* 例如:
* R 1 1
* W 2 1 1
*/
typedef struct {
int tid;
int continueTime;
int writeData;
}WriterParameter;
typedef struct {
int tid;
int continueTime;
}ReaderParameter;
pthread_t readers[N_READER], writers[N_WRITER];
ReaderParameter rp[N_READER];
WriterParameter wp[N_WRITER];
pthread_mutex_t mutex_write, mutex_read;
sem_t sem_read, sem_write;
int data = 0; // 初始化数据
int readerCnt = 0, writerCnt = 0;
void print_help(char *argv[]) {
printf("Usage: %s [-rw] -t <file>\n", argv[0]);
printf("Options:\n");
printf(" -h Print this help message.\n");
printf(" -r reader first.\n");
printf(" -w writer first.\n");
printf(" -t <file> test file.\n");
printf("Examples:\n");
printf("linux> %s -r test.txt\n", argv[0]);
}
void write(int writeData) {
printf("write data: %d to %d\n", data, writeData);
data = writeData;
}
void read() {
printf("read data: %d\n",data);
}
// 读者优先(rf)的读者行为
void *reader_rf (void *rp) {
// 获得写锁的过程不能和其他读者并发,用信号量保护
sem_wait(&sem_read);
readerCnt++;
// 凡是有读者,就获得写锁,后来的写者必须等待。
if(readerCnt == 1)
pthread_mutex_lock(&mutex_write);
sem_post(&sem_read);
// 开始读
printf("reader %d start reading\n", ((ReaderParameter *)rp)->tid);
read();
sleep(((ReaderParameter *)rp)->continueTime);
printf("reader %d finish reading\n", ((ReaderParameter *)rp)->tid);
sem_wait(&sem_read);
readerCnt--;
if(readerCnt == 0)
pthread_mutex_unlock(&mutex_write);
sem_post(&sem_read);
pthread_exit(NULL);
}
// 读者优先(rf)的写者行为
void *writer_rf(void *wp) {
sem_wait(&sem_write);
writerCnt++;
if(writerCnt == 1){
// 凡有写者,就获得读锁,以阻止后来的读者读
pthread_mutex_lock(&mutex_read);
}
sem_post(&sem_write);
// 获得写锁,只有一个写者修改数据
pthread_mutex_lock(&mutex_write);
printf("writer %d start writing\n", ((WriterParameter *)wp)->tid);
write(((WriterParameter *)wp)->writeData);
sleep(((WriterParameter *)wp)->continueTime);
printf("writer %d finish writing\n", ((WriterParameter *)wp)->tid);
pthread_mutex_unlock(&mutex_write);
pthread_exit(NULL);
}
// 写者优先(wf)的读者行为
void *reader_wf (void *rp) {
// 假如writer锁定了mutex_read,那么其他所有reader被阻塞在这里
pthread_mutex_lock(&mutex_read); //只被一个reader占有
sem_wait(&sem_read);
readerCnt++;
if (readerCnt == 1)
pthread_mutex_lock(&mutex_write);
sem_post(&sem_read);
pthread_mutex_unlock(&mutex_read); // 释放时,写者将优先获得读锁
printf("reader %d start reading\n", ((ReaderParameter *)rp)->tid);
read();
sleep(((ReaderParameter *)rp)->continueTime);
printf("reader %d finish reading\n", ((ReaderParameter *)rp)->tid);
sem_wait(&sem_read);
readerCnt--;
// 最后一个读者读完开始允许写者执行写操作
if (readerCnt == 0)
pthread_mutex_unlock(&mutex_write);
sem_post(&sem_read);
pthread_exit(NULL);
}
// 写者优先(wf)的写者行为
void *writer_wf(void *wp) {
sem_wait(&sem_write);
writerCnt++;
if(writerCnt == 1){
// 凡有写者,就获得读锁,以阻止后来的读者读
pthread_mutex_lock(&mutex_read);
}
sem_post(&sem_write);
// 获得写锁,只有一个写者修改数据
pthread_mutex_lock(&mutex_write);
printf("writer %d start writing\n", ((WriterParameter *)wp)->tid);
write(((WriterParameter *)wp)->writeData);
sleep(((WriterParameter *)wp)->continueTime);
printf("writer %d finish writing\n", ((WriterParameter *)wp)->tid);
pthread_mutex_unlock(&mutex_write);
sem_wait(&sem_write);
writerCnt--;
//允许后续的读者加入待读队列
if (writerCnt == 0)
pthread_mutex_unlock(&mutex_read);
sem_post(&sem_write);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
pthread_mutex_init(&mutex_write,NULL);
pthread_mutex_init(&mutex_read,NULL);
// int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value))
// pshared为0,表示只能为当前进程的所有线程共享;
// value为信号量的初始值
sem_init(&sem_read,0,1);
sem_init(&sem_write,0,1);
// 函数指针
// 默认策略为写者优先
void (*reader) (void *param) = reader_wf;
void (*writer) (void *param) = writer_wf;
char c; char *file = NULL;
while ((c = getopt(argc, argv, "hrwt:")) != -1) {
switch (c) {
case 'r':
reader = reader_rf;
writer = writer_rf;
break;
case 'w':
break;
case 't':
file = optarg;
break;
case 'h':
default:
print_help(argv);
return 0;
}
}
// 打开测试文件
FILE *fp = NULL;
if ((fp = fopen(file, "r")) == NULL) {
printf("%s: No such file or directory\n", file);
return 0;
}
int i = 0, j = 0; // i和j分别表示读者和写者线程
// 读取测试文件
while ((c = fgetc(fp)) != EOF) {
char buf[20];
// 读者
// 格式为:"R tid continueTIme"
if (c == 'R') {
fgetc(fp); // jump the space
fgets(buf, 20, fp);
rp[i].tid = atoi(strtok(buf, " "));
rp[i].continueTime = atoi(strtok(NULL, " "));
pthread_t reader_t;
pthread_create(&readers[i++], NULL, reader, &rp[i++]);
}
// 写者
// 格式为:"R tid continueTIme writeData"
else {
fgetc(fp);
fgets(buf, 20, fp);
wp[j].tid = atoi(strtok(buf, " "));
wp[j].continueTime = atoi(strtok(NULL, " "));
wp[j].writeData = atoi(strtok(NULL, " "));
pthread_t writer_t;
pthread_create(&writers[j++], NULL, writer, &wp[j++]);
}
}
sleep(10);
return 0;
}
下面是我的测试文件:
R 1 2
W 2 1 1
R 3 3
R 4 1
W 5 2 2