问题描述:


用读者和写者来模拟并行计算的过程:

  • 读者在读的时候,写者不能写,必须等到读者读完
  • 多个读者可以读一本书
  • 同时只能一个作者在写
  • 在写的时候,读者不能读

问题分析:


  • 作品是共享的资源,作者和读者要竞争这个资源,要避免决策导致某一方被饿死(长时间竞争不到资源)。
  • 共享资源是简单的只能有一个人能使用,而是在读者读的时候能够多人同时共享资源,在写者占有资源的时候,只能有一个写者持有这个资源

基本思路:

  • 最基本的想法使采取一般的进程同步互斥问题的思路,也就是信号量的最基本的用法:
  • 定义一个互斥量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 );
    }
}