读者-写者问题是进程同步的经典问题。
要求读读同时,读写互斥,写写互斥。
多个读线程允许同时访问临界资源,读文件。写线程与读线程不能同时使用文件临界资源进行操作,并且多个写线程不能同时对临界资源进行操作。
读者优先
当多个读线程与多个写线程排队时,总是读线程优于写线程先得到文件临界资源使用权。
文件资源用互斥信号量wmutex控制,初始值为1。
添加一个计数器readcount,记录当前读进程的数量。进来一个进程,readcount+1,走一个进程readcount-1。第一个进入的进程readcount=0,申请文件资源使用权,最后一个走的进程readcount=0,释放文件资源使用权。
文件的使用权只需要第一个读线程申请到就行,后面读线程不需要申请,能直接使用,保证读读同时,读写互斥。
readcount是多个读者进程共享的临界资源。互斥信号量rmutex控制。初始值1。
P():申请资源 V():释放资源
int readcount = 0; //计数器,初始化值为0
semaphore rmutex = 1,dmutex = 1; //readcount信号量,文件信号量
读者进程:
P(rmutex); //申请readcount资源使用权
if(readcount == 0) //readcount为0,就是第一个进入的读线程,申请文件使用权
P(dmutex); //申请文件资源的使用权
readcount++;
V(rmutex);
read document...
P(rmutex);
readcount--;
if(readcount == 0) //readcount=0,就是最后一个使用的读线程,释放文件使用权
V(dmutex);
V(rmutex);
写者进程:
P(dmutex);
write document...
V(dmutex);
写者优先
写者优先的策略,是在读者优先的基础上改变的。
设计是是在读者的进程开始设置一个互斥信号量mutex1,初始值为1,目的是如果第一个获取文件资源的使读者进程时,将后面的中的读者进程全都阻塞在muetx1这队列中。
如果想达到写者优先,可以重新设置一个互斥信号量rob,初始值为1。这个资源在读者与写者进程都可以申请,并且需要满足写者进程肯定会在在读者进程之前获得,那么就用到了上面的mutex1,可以将读者进程都堵塞在mutex1上,在读者进程中让rob先于mutex释放,就可以做到写者进程优先于读者进程。
整个思想就是在文件临界资源外再设置一个门,这个门就是mutex1,读者进程每次都需要在这个门后等待这个资源释放才有资格申请抢夺文件临界资源,而写者进程可以越过这门,直接等待申请文件临界资源。
还要设置一个writecount计数器,记录写者进程的数量,直到所有写者进程退出后,最后一个退出的写者进程释放文件资源的使用权。
当然写者进程在使用文件临界资源时,也是互斥访问的,都需要先申请临界资源使用权。
int readcount = 0,writecount = 0; //读者,写者计数器,初始化值为0
semaphore rmutex = 1, //readcount信号量
wmutex = 1, //writecount信号量
dmutex = 1, //文件资源信号量
rob = 1, //读写进程抢夺的信号量
mutex1 = 1;//将读者进程堵塞在队列中的信号量
读者进程:
P(mutex1);
P(rob);
P(rmutex);
if(readcount == 0)
P(dmutex);
readcount++;
V(rmutex);
V(rob);
V(mutex1);
read ducoment...
P(rmutex);
readcount--;
if(readcount == 0)
V(dmutex);
V(rmutex);
写者进程:
P(wmutex);
if(writecount == 0)
P(rob);
writecount++;
V(wmutex);
P(dmutex);
write ducoment...
V(dmutex);
P(wmutex)
writecount--;
if(writecount == 0)
V(rob);
V(wmutex);
读写顺序执行
实现读写顺序执行,让进程按照在阻塞对列的顺序执行。只需要在读写进程在进程开始竞争一个临界资源,所有进程都在这个阻塞队列排队。保证读读同时与读写互斥,写写互斥
。
这样无论在阻塞队列中读写进程的顺序是怎样的,都能按照排队顺序来执行。
这个互斥信号量用mutex2表示,初始值为1。
int readcount = 0;
semaphore rmutex = 1,dmutex = 1,mutex2 = 1;
读者进程
P(mutex2);
P(rmutex);
if(readccount == 0)
P(dmutex);
readcount++;
V(rmutex);
V(mutex2);
read ducoment...
P(rmutex);
readcount--;
if(readcount == 0)
V(dmutex);
V(rmutex);
写者进程
P(mutex2);
P(dmutex);
write ducoment...
V(dmutex);
V(mutex2);