要求:
为了防止“读者优先”可能导致的写者饥饿,可以考虑写者优先。即,当共享数据区被读者占用时,后续紧邻到达的读者可以继续进入,若这时有一个写者到来并阻塞等待,则写者后续到来的读者全部阻塞等待。即只要有一个写者申请写数据,则不再允许新的读者进程进入读数据。这样,写者只需等待先于它到达的读者完成其读数据的任务,而不用等待其后到达的读者。
新读者:
如果无读者、写者,新读者可以读。
如果有写者等待,且有其它读者正在读,新读者等待。
如果有写者写,新读者等待。
新写者:
如果无读者,新写者可以写。
如果有读者,新写者等待。
如果有其它写者,新写者等待。
思路:
同读者优先有一些类似,写者优先也需要用一个整型变量Readcount记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当Readcount=0时,表明所有的读者都已经读完,需要释放写者等待队列中的一个写者)。在每一个读者读文件之前,都必须修Readcount变量的值(增一),在每一个读者读完文件之后,也必须修改Readcount变量的值(减一)。因此需要一个互斥对象Rmutex来实现对
全局变量Readcount修改时的互斥。
为了实现写-写互斥,需要增加一个写互斥信号量Wmutex。保证写进程与其它进程写互斥地访问数据集。
另外,还需要增加一个信号量 S,初值为 1,用来实现读写互斥,使写者请求发生后的读者等待。
综上,设置一个共享变量和三个互斥信号量。
共享变量 Readcount:记录当前正在读数据集的读进程数目,初值为 0。
读互斥信号量 Rmutex :表示读进程互斥地访问共享变量 Readcount,初值为 1。
写互斥信号量 Wmutex:表示写进程与其它进程(读、写)互斥地访问数据集,初值为 1。
读写互斥信号量 S :表示读进程和写进程互斥地访问数据集,初值为 1。
//写者优先
# include
# include
# include
# include
# include
# include
# include
# include
sem_t Rmutex,Wmutex, S;
int readCount;
struct data {
int id;
int opTime;
int lastTime;
};
//读者
void* Reader(void* param) {
int id = ((struct data*)param)->id;
int lastTime = ((struct data*)param)->lastTime;
int opTime = ((struct data*)param)->opTime;
sleep(opTime);
printf("Thread %d: waiting to read\n", id);
sem_wait(&S);
sem_wait(&Rmutex);
readCount++;
if(readCount == 1)
sem_wait(&Wmutex);
sem_post(&Rmutex);
sem_post(&S);
//执行读操作
printf("Thread %d: start reading\n", id);
sleep(lastTime);
printf("Thread %d: end reading\n", id);
sem_wait(&Rmutex);
readCount--;
if(readCount == 0)
sem_post(&Wmutex);
sem_post(&Rmutex);
pthread_exit(0);
}
//写者
void* Writer(void* param) {
int id = ((struct data*)param)->id;
int lastTime = ((struct data*)param)->lastTime;
int opTime = ((struct data*)param)->opTime;
sleep(opTime);
printf("Thread %d: waiting to write\n", id);
sem_wait(&S);
sem_wait(&Wmutex);
//执行写操作
printf("Thread %d: start writing\n", id);
sleep(lastTime);
printf("Thread %d: end writing\n", id);
sem_post(&Wmutex);
sem_post(&S);
pthread_exit(0);
}
int main() {
pthread_t tid;
//初始化信号量
sem_init(&Rmutex, 0, 1);
sem_init(&Wmutex, 0, 1);
sem_init(&S, 0, 1);
readCount = 0;
int id = 0;
while(scanf("%d", &id) != EOF) {
char role; //读者还是写者
int opTime; //每个进程执行间隔时间
int lastTime; //读/写的时间
scanf("%c%d%d", &role, &opTime, &lastTime);
struct data* d = (struct data*)malloc(sizeof(struct data));
d->id = id;
d->opTime = opTime;
d->lastTime = lastTime;
if(role == 'R') {
printf("Create the %d thread: Reader\n", id);
pthread_create(&tid, NULL, Reader, d);
}
else if(role == 'W') {
printf("Create the %d thread: Writer\n", id);
pthread_create(&tid, NULL, Writer, d);
}
}
sem_destroy(&S);
sem_destroy(&Rmutex);
sem_destroy(&Wmutex);
return 0;
}
要求:
当一个读者正在读数据时,另一个读者也需要读数据,应允许第二个读者进入,同理第三个及后续读者都应允许进入。现在假设一个写者到来,由于写操作是排他的,所以它不能访问数据,需要阻塞等待。如果一直有新的读者陆续到来,写者的写操作将被严重推迟。该方法称为“读者优先”,即一旦有读者正在读数据,只有当全部读者退出,才允许写者进入写数据。
新读者:
如果无读者、写者,新读者可以读。
如果有写者等待,但有其它读者正在读,则新读者也可以读。
如果有写者写,新读者等待。
新写者:
如果无读者,新写者可以写。
如果有读者,新写者等待。
如果有其它写者,新写者等待。
思路:
读者优先指的是除非有写者在写文件,否则读者不需要等待。所以可以用一个整型变量Readcount记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当Readcount=0时,表明所有的读者都已经读完,需要释放写者等待队列中的一个写者)。在每一个读者读文件之前,都必须修改Readcount变量的值(增一),在每一个读者读完文件之后,也必须修改Readcount变量的值(减一)。因此需要一个互斥对象Rmutex来实现对全局变量Readcount修改时的互斥。
另外,为了实现写-写互斥,需要增加一个写互斥信号量Wmutex。保证写进程与其它写进程互斥地访问数据集。
通过这种方法,也可以实现读-写互斥,当Readcount=1时(即第一个读者到来时),读者线程也必须P(Wmutex),此时写者阻塞。当写者P(Wmutex)后,接下来再到来的第一个读者判断完Readcount=1后阻塞在P(Wmutex)这一步上无法释放Rmutex,其余的读者由于等待第一个读者对Rmutex的释放而阻塞在P(Rmutex)上。
综上,设置一个共享变量和两个互斥信号量。
共享变量 Readcount:记录当前正在读数据集的读进程数目,初值为 0。
读互斥信号量 Rmutex :表示读进程互斥地访问共享变量 Readcount,初值为 1。
写互斥信号量 Wmutex:表示写进程与其它进程(读、写)互斥地访问数据集,初值为 1。
// 读者优先
# include
# include
# include
# include
# include
# include
# include
# include
sem_t Rmutex,Wmutex;
int readCount;
struct data {
int id;
int opTime;
int lastTime;
};
//读者
void* Reader(void* param) {
int id = ((struct data*)param)->id;
int lastTime = ((struct data*)param)->lastTime;
int opTime = ((struct data*)param)->opTime;
sleep(opTime);
printf("Thread %d: waiting to read\n", id);
sem_wait(&Rmutex);
readCount++;
if(readCount == 1)
sem_wait(&Wmutex);
sem_post(&Rmutex);
//执行读操作
printf("Thread %d: start reading\n", id);
sleep(lastTime);
printf("Thread %d: end reading\n", id);
sem_wait(&Rmutex);
readCount--;
if(readCount == 0)
sem_post(&Wmutex);
sem_post(&Rmutex);
pthread_exit(0);
}
//写者
void* Writer(void* param) {
int id = ((struct data*)param)->id;
int lastTime = ((struct data*)param)->lastTime;
int opTime = ((struct data*)param)->opTime;
sleep(opTime);
printf("Thread %d: waiting to write\n", id);
sem_wait(&Wmutex);
//执行写操作
printf("Thread %d: start writing\n", id);
sleep(lastTime);
printf("Thread %d: end writing\n", id);
sem_post(&Wmutex);
pthread_exit(0);
}
int main() {
pthread_t tid;
//初始化信号量
sem_init(&Rmutex, 0, 1);
sem_init(&Wmutex, 0, 1);
readCount = 0;
int id = 0;
while(scanf("%d", &id) != EOF) {
char role; //读者还是写者
int opTime; //每一个进程开始前的间隔时间
int lastTime; //执行读/写操作的时间
scanf("%c%d%d", &role, &opTime, &lastTime);
struct data* d = (struct data*)malloc(sizeof(struct data));
d->id = id;
d->opTime = opTime;
d->lastTime = lastTime;
if(role == 'R') {
printf("Create the %d thread: Reader\n", id);
pthread_create(&tid, NULL, Reader, d);
}
else if(role == 'W') {
printf("Create the %d thread: Writer\n", id);
pthread_create(&tid, NULL, Writer, d);
}
}
//信号量销毁
sem_destroy(&Rmutex);
sem_destroy(&Wmutex);
return 0;
}