0


经典进程同步问题——读者写者问题

问题描述

写者优先

要求:
为了防止“读者优先”可能导致的写者饥饿,可以考虑写者优先。即,当共享数据区被读者占用时,后续紧邻到达的读者可以继续进入,若这时有一个写者到来并阻塞等待,则写者后续到来的读者全部阻塞等待。即只要有一个写者申请写数据,则不再允许新的读者进程进入读数据。这样,写者只需等待先于它到达的读者完成其读数据的任务,而不用等待其后到达的读者。

新读者:
如果无读者、写者,新读者可以读。
如果有写者等待,且有其它读者正在读,新读者等待。
如果有写者写,新读者等待。

新写者:
如果无读者,新写者可以写。
如果有读者,新写者等待。
如果有其它写者,新写者等待。

思路:
同读者优先有一些类似,写者优先也需要用一个整型变量Readcount记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当Readcount=0时,表明所有的读者都已经读完,需要释放写者等待队列中的一个写者)。在每一个读者读文件之前,都必须修Readcount变量的值(增一),在每一个读者读完文件之后,也必须修改Readcount变量的值(减一)。因此需要一个互斥对象Rmutex来实现对
全局变量Readcount修改时的互斥。
为了实现写-写互斥,需要增加一个写互斥信号量Wmutex。保证写进程与其它进程写互斥地访问数据集。
另外,还需要增加一个信号量 S,初值为 1,用来实现读写互斥,使写者请求发生后的读者等待。

综上,设置一个共享变量和三个互斥信号量。
共享变量 Readcount:记录当前正在读数据集的读进程数目,初值为 0。
读互斥信号量 Rmutex :表示读进程互斥地访问共享变量 Readcount,初值为 1。
写互斥信号量 Wmutex:表示写进程与其它进程(读、写)互斥地访问数据集,初值为 1。
读写互斥信号量 S :表示读进程和写进程互斥地访问数据集,初值为 1。

//写者优先#include<stdio.h>#include<stdlib.h>#include<time.h>#include<sys/types.h>#include<pthread.h>#include<semaphore.h>#include<string.h>#include<unistd.h>sem_t Rmutex,Wmutex, S;int readCount;structdata{int id;int opTime;int lastTime;};//读者void*Reader(void* param){int id =((structdata*)param)->id;int lastTime =((structdata*)param)->lastTime;int opTime =((structdata*)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 =((structdata*)param)->id;int lastTime =((structdata*)param)->lastTime;int opTime =((structdata*)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);}intmain(){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);structdata* d =(structdata*)malloc(sizeof(structdata));

        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);}elseif(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);return0;}

读者优先

要求:
当一个读者正在读数据时,另一个读者也需要读数据,应允许第二个读者进入,同理第三个及后续读者都应允许进入。现在假设一个写者到来,由于写操作是排他的,所以它不能访问数据,需要阻塞等待。如果一直有新的读者陆续到来,写者的写操作将被严重推迟。该方法称为“读者优先”,即一旦有读者正在读数据,只有当全部读者退出,才允许写者进入写数据。

新读者:
如果无读者、写者,新读者可以读。
如果有写者等待,但有其它读者正在读,则新读者也可以读。
如果有写者写,新读者等待。
新写者:
如果无读者,新写者可以写。
如果有读者,新写者等待。
如果有其它写者,新写者等待。

思路:
读者优先指的是除非有写者在写文件,否则读者不需要等待。所以可以用一个整型变量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<stdio.h>#include<stdlib.h>#include<time.h>#include<sys/types.h>#include<pthread.h>#include<semaphore.h>#include<string.h>#include<unistd.h>sem_t Rmutex,Wmutex;int readCount;structdata{int id;int opTime;int lastTime;};//读者void*Reader(void* param){int id =((structdata*)param)->id;int lastTime =((structdata*)param)->lastTime;int opTime =((structdata*)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 =((structdata*)param)->id;int lastTime =((structdata*)param)->lastTime;int opTime =((structdata*)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);}intmain(){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);structdata* d =(structdata*)malloc(sizeof(structdata));

        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);}elseif(role =='W'){printf("Create the %d thread: Writer\n", id);pthread_create(&tid,NULL, Writer, d);}}//信号量销毁sem_destroy(&Rmutex);sem_destroy(&Wmutex);return0;}
标签:

本文转载自: https://blog.csdn.net/qiankendeNMY/article/details/118933891
版权归原作者 薛铁钢 所有, 如有侵权,请联系我们删除。

“经典进程同步问题——读者写者问题”的评论:

还没有评论