📜  使用监视器的读写器解决方案

📅  最后修改于: 2021-09-28 10:09:01             🧑  作者: Mango

先决条件——进程同步、监视器、读写器问题
考虑到共享数据库,我们的目标是:

  • 读者只有在没有作者的情况下才能访问数据库。
  • 只有在没有读者或作者的情况下,作者才能访问数据库。
  • 一次只有一个线程可以操作状态变量。

解决方案的基本结构 –

Reader()
   Wait until no writers
   Access database
   Check out – wake up a waiting writer
Writer()
   Wait until no active readers or writers
   Access database
   Check out – wake up waiting readers or writer

– 现在让我们假设一个作家是活跃的,现在出现了读者和作家的混合体。
谁应该进入下一个?
– 或者假设一位作家正在等待,而无穷无尽的读者不断出现。
他们变得活跃是否公平?
所以我们将实现一种来回公平的形式:

  • 一旦有读者在等待,下一个读者就会进来。
  • 如果一位作家在等待,下一位作家会进来。

使用监视器实施解决方案:-

  1. 这些方法应该相互排斥地执行,即在每个时间点,最多有一个线程可以执行它的任何方法。
  2. 监视器还为线程提供了一种机制,可以暂时放弃独占访问,以便在重新获得独占访问并恢复其任务之前等待满足某些条件。
  3. 监视器也有一种机制来通知其他线程已经满足这些条件。
  4. 所以在这个实现中只有互斥是不够的。尝试操作的线程可能需要等到某个断言 P 为真。
  5. 当一个线程正在等待一个条件变量时,该线程不被认为占用监视器,因此其他线程可能进入监视器以更改监视器的状态。

代码 –

// STATE VARIABLES
// Number of active readers; initially = 0
int NReaders = 0;
  
// Number of waiting readers; initially = 0
int WaitingReaders = 0;
  
// Number of active writers; initially = 0
int NWriters = 0;
  
// Number of waiting writers; initially = 0
int WaitingWriters = 0;
  
Condition canRead = NULL;
Condition canWrite = NULL;
  
Void BeginWrite()
{
  
    // A writer can enter if there are no other
    // active writers and no readers are waiting
    if (NWriters == 1 || NReaders > 0) {
  
        ++WaitingWriters;
        wait(CanWrite);
        --WaitingWriters;
    }
  
    NWriters = 1;
}
  
Void EndWrite()
{
  
    NWriters = 0;
  
    // Checks to see if any readers are waiting
    if (WaitingReaders)
  
        Signal(CanRead);
  
    else
  
        Signal(CanWrite);
}
  
Void BeginRead()
{
  
    // A reader can enter if there are no writers
    // active or waiting, so we can have
    // many readers active all at once
    if (NWriters == 1 || WaitingWriters > 0) {
  
        ++WaitingReaders;
  
        // Otherwise, a reader waits (maybe many do)
        Wait(CanRead);
  
        --WaitingReaders;
    }
  
    ++NReaders;
    Signal(CanRead);
}
  
Void EndRead()
{
  
    // When a reader finishes, if it was the last reader,
    // it lets a writer in (if any is there).
    if (--NReaders == 0)
  
        Signal(CanWrite);
}

了解解决方案:-

  • 它想要公平。
  1. 如果作者在等待,读者会排队。
  2. 如果读者(或其他作者)处于活动或等待状态,则作者会排队。
  3. 这基本上是公平的,尽管一旦它让读者进入,它就会让所有等待的读者同时进入,即使有些人“在”其他等待的作者之后出现。


  • 代码被“简化”了,因为我们知道一次只能有一个作者。

  • 它还利用了这样一个事实,即如果没有人在等待,信号就是空操作。
    1. 在“EndWrite”代码中(它在不检查等待写入者的情况下向 CanWrite 发出信号)
    2. 在 EndRead 代码中(同样的事情)
    3. 在 StartRead 中(最后发出 CanRead 信号)