问题描述:
用读者和写者来模拟并行计算的过程:
- 读者在读的时候,写者不能写,必须等到读者读完
- 多个读者可以读一本书
- 同时只能一个作者在写
- 在写的时候,读者不能读
问题分析:
- 作品是共享的资源,作者和读者要竞争这个资源,要避免决策导致某一方被饿死(长时间竞争不到资源)。
- 共享资源不是简单的只能有一个人能使用,而是在读者读的时候能够多人同时共享资源,在写者占有资源的时候,只能有一个写者持有这个资源
基本思路:
- 最基本的想法使采取一般的进程同步互斥问题的思路,也就是信号量的最基本的用法:
- 定义一个互斥量mutex,与作品资源绑定,每次只能有一个进程(线程)利用这个资源
- 但是这种方法明显忽略一个特点,就是读者处于浏览作品的时候,是可以多个读者同时,这种方法明显会造成资源的浪费
- 然后考虑的读者优先的方案:
- 定义一个互斥量mutex与作品资源绑定,但是不再限定每次只有一个进程(线程)利用这个资源,采取的策略是定义一个numReader的共享的变量来记录当前读者个数(既然是一个共享的变量,那么自然需要一个互斥量,来保证同步过程中同时只有一个进程在修改它)。
- 有一个新的读者的时候首先查看当前读者的总数
- 如果新来的读者不是第一读者,那么他不需要检查互斥锁,直接可以参与到阅读中
- 如果新来的读者是第一读者,那么他需要检查互斥锁,如果锁住了,说明有作者在修改,那么等待作者写完再读,先睡觉,如果没锁住,那么开始阅读,并且将锁锁住
- 写者的操作就是简单地检查互斥锁
- 那么这种方案,因为是写者优先,所以可能导致作者饿死。
- 再考虑写者优先的解决方案:
- 定义一个互斥量mutex与作品资源绑定,但是不再限定每次只有一个进程(线程)利用这个资源。
- 定义rdMutex来绑定记录读者数量的互斥量,定义rwMutex来记录当前是否有写者在等着写或者正在写。
- 那么读者在每次阅读前,都要检查是否有写者要写,如果有,那么他先睡觉,等写者写完他才开始写,如果一直有写者,那么他可能饿死
- 这种方案其他的操作与写者优先的无异,但是这种做法已经有很稳定和高效的并行性
代码如下:
- 读者优先的读者-写者问题解决方案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#define p(x) sem_wait(&x)
#define v(x) sem_post(&x)
#define MAX 20
int numReader;
sem_t mutex,rdMutex;
void init ( )
{
numReader = 0;
sem_init ( &mutex , 0 , 1 );
sem_init ( &rdMutex , 0 , 1 );
}
void* reader ( void* arg )
{
int* p = (int*)arg;
int x = *p;
p(rdMutex);
if ( numReader == 0 )
p(mutex);
numReader++;
v(rdMutex);
printf ( "The %dth reader reading....\n" , x );
sleep(2);
p(rdMutex);
numReader--;
if ( numReader == 0 )
v(mutex);
v(rdMutex);
}
void* writer ( void* arg )
{
int*p = (int*)arg;
int x = *p;
p(mutex);
printf ( "The %dth writer editing...\n" , x );
sleep(3);
v(mutex);
}
int main( )
{
init ();
int i,j=1;
pthread_t rid[MAX];
pthread_t wid[MAX];
int rid1[MAX];
int wid1[MAX];
for ( i = 0 ; i < MAX ;i ++ )
{
rid1[i] = i;
wid1[i] = i;
pthread_create ( &rid[i] , NULL , reader , &rid1[i] );
pthread_create ( &wid[i] , NULL , writer , &wid1[i] );
sleep(2);
}
for ( i = 0 ; i < MAX ;i ++ )
{
pthread_join ( rid[i] , NULL );
pthread_join ( wid[i] , NULL );
}
}
- 写者优先的读者-写者问题解决方案
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <semaphore.h>
#include <pthread.h>
#define MAX 20
#define p(x) sem_wait(&x)
#define v(x) sem_post(&x)
int numReader;
sem_t rdMutex,wtMutex,mutex;
void init ( )
{
numReader = 0;
sem_init ( &rdMutex , 0 , 1 );
sem_init ( &wtMutex , 0 , 1 );
sem_init ( &mutex , 0 , 1 );
}
void* reader ( void* arg )
{
int *p = (int*)arg;
int x = *p;
p(wtMutex);
p(rdMutex);
if ( numReader == 0 )
p(mutex);
numReader++;
v(rdMutex);
v(wtMutex);
printf ( "The %dth reader reading....\n" , x );
sleep(2);
p(rdMutex);
numReader--;
if ( numReader == 0 )
v(mutex);
v(rdMutex);
}
void* writer ( void* arg )
{
int *p = (int*)arg;
int x = *p;
p(wtMutex);
p(mutex);
printf ( "The %dth writer editing....\n" , x );
sleep(4);
v(mutex);
v(wtMutex);
}
int main ( )
{
init ();
pthread_t rid[MAX];
pthread_t wid[MAX];
pthread_t rid1[MAX];
pthread_t wid1[MAX];
int i;
for ( i = 0 ; i < MAX ; i++ )
{
rid1[i] = wid1[i] = i;
pthread_create ( &rid[i] , NULL , reader , &rid1[i] );
pthread_create ( &wid[i] , NULL , writer , &wid1[i] );
sleep(1);
}
for ( i = 0 ; i < MAX ; i++ )
{
pthread_join ( rid1[i] , NULL );
pthread_join ( wid1[i] , NULL );
}
}