作家-读者问题

问题描述:允许多个进程同时对数据进行读操作,但是不允许读和写以及写和写操作同时发生。

信号量:一个整型变量 count 记录在对数据进行读操作的进程数量,一个互斥量 count_mutex 用于对 count 加锁,一个互斥量 data_mutex 用于对读写的数据加锁。

简单信号量版本

typedef int semaphore;
semaphore count_mutex = 1;
semaphore data_mutex = 1;
int count = 0;

void reader() {
    while(TRUE) {
        down(&count_mutex);
        count++;
        if(count == 1) down(&data_mutex); // 第一个读者需要对数据进行加锁,防止写进程访问
        up(&count_mutex);
        read();
        down(&count_mutex);
        count--;
        if(count == 0) up(&data_mutex);
        up(&count_mutex);
    }
}

void writer() {
    while(TRUE) {
        down(&data_mutex);
        write();
        up(&data_mutex);
    }
}

上面这种可能导致一些情况。

第一种情况可能导致作家饿死。这种情况下,喜欢写文章的人,即任何一个写文章的人,一旦加入队列,等待的时间都不得超过绝对必要的时间(只有当有读者在作者之前进入队列时),因为读者阅读后,对数据加锁,作家不能写。

所以有了version 2.0:

int readcount, writecount;                   //(initial value = 0)初始值为0
semaphore rmutex, wmutex, readLock, resource; //(initial value = 1)初始值为1

//READER
void reader() {

 down(&readLock);                 //  reader is trying to enter 读者进入,
 down(&rmutex);                  //   lock to increase readcount 读者,down锁,互斥,防止多读者修改信号量
  readcount++;                 //读者数量+1
  if (readcount == 1)          //如果是第一个读者,就要锁上文章,不让作家修改
   down(&resource);              //if you are the first reader then lock  the resource
 up(&rmutex);                  //release  for other readers解锁,其他读者可以读了
 up(&readLock);                 //Done with trying to access the resource


//reading is performed  //读者阅读


 down(&rmutex);                  //reserve exit section - avoids race condition with readers
 readcount--;                       //indicate you're leaving
  if (readcount == 0)          //checks if you are last reader leaving
   up(&resource);              //if last, you must release the locked resource
 up(&rmutex);                  //release exit section for other readers
}

//WRITER
void writer() {
  
  down(&wmutex);                  //reserve entry section for writers - avoids race conditions
  writecount++;                //report yourself as a writer entering
  if (writecount == 1)         //checks if you're first writer
   down(&readLock);               //if you're first, then you must lock the readers out. Prevent them from trying to enter CS
  up(&wmutex);                  //release entry section


 down(&resource);                //reserve the resource for yourself - prevents other writers from simultaneously editing the shared resource
  //writing is performed
 up(&resource);                //release file


  down(&wmutex);                  //reserve exit section
  writecount--;                //indicate you're leaving
  if (writecount == 0)         //checks if you're the last writer
   up(&readLock);               //if you're last writer, you must unlock the readers. Allows them to try enter CS for reading
  up(&wmutex);                  //release exit section
}

我们可以看到,每个读者都被迫获得ReadLock。另一方面,作者不需要单独锁定。一旦第一个writer锁定ReadLock,它将仅在队列中没有writer时释放。

从这两个案例中,我们发现读者或作家都必须挨饿。下面的解决方案添加了一个约束,即不允许任何线程饿死;也就是说,获取共享数据锁的操作总是在有限的时间内终止。

Version 3.0

int readCount;                  // init to 0; number of readers currently accessing resource

// all semaphores initialised to 1
Semaphore resourceAccess;       // controls access (read/write) to the resource
Semaphore readCountAccess;      // for syncing changes to shared variable readCount
Semaphore serviceQueue;         // FAIRNESS: preserves ordering of requests (signaling must be FIFO)

void writer()
{ 
    down(&serviceQueue);           // wait in line to be servicexs
    // 
    down(&resourceAccess);         // request exclusive access to resource
    // 
    up(&serviceQueue);           // let next in line be serviced

    // 
    writeResource();            // writing is performed
    // 

    // 
    up(&resourceAccess);         // release resource access for next reader/writer
    // 
}

void reader()
{ 
    down(&serviceQueue);           // wait in line to be serviced
    down(&readCountAccess);        // request exclusive access to readCount
    // 
    if (readCount == 0)         // if there are no readers already reading:
        down(&resourceAccess);     // request resource access for readers (writers blocked)
    readCount++;                // update count of active readers
    // 
    up(&serviceQueue);           // let next in line be serviced
    up(&readCountAccess);        // release access to readCount

    // 
    readResource();             // reading is performed
    // 

    down(&readCountAccess);        // request exclusive access to readCount
    // 
    readCount--;                // update count of active readers
    if (readCount == 0)         // if there are no readers left:
        up(&resourceAccess);     // release resource access for all
    // 
    up(&readCountAccess);        // release access to readCount
}

 

你可能感兴趣的:(操作系统)