先决条件——进程同步、监视器、读写器问题
考虑到共享数据库,我们的目标是:
- 读者只有在没有作者的情况下才能访问数据库。
- 只有在没有读者或作者的情况下,作者才能访问数据库。
- 一次只有一个线程可以操作状态变量。
解决方案的基本结构 –
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
– 现在让我们假设一个作家是活跃的,现在出现了读者和作家的混合体。
谁应该进入下一个?
– 或者假设一位作家正在等待,而无穷无尽的读者不断出现。
他们变得活跃是否公平?
所以我们将实现一种来回公平的形式:
- 一旦有读者在等待,下一个读者就会进来。
- 如果一位作家在等待,下一位作家会进来。
使用监视器实施解决方案:-
- 这些方法应该相互排斥地执行,即在每个时间点,最多有一个线程可以执行它的任何方法。
- 监视器还为线程提供了一种机制,可以暂时放弃独占访问,以便在重新获得独占访问并恢复其任务之前等待满足某些条件。
- 监视器也有一种机制来通知其他线程已经满足这些条件。
- 所以在这个实现中只有互斥是不够的。尝试操作的线程可能需要等到某个断言 P 为真。
- 当一个线程正在等待一个条件变量时,该线程不被认为占用监视器,因此其他线程可能进入监视器以更改监视器的状态。
代码 –
// 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);
}
了解解决方案:-
- 它想要公平。
- 如果作者在等待,读者会排队。
- 如果读者(或其他作者)处于活动或等待状态,则作者会排队。
- 这基本上是公平的,尽管一旦它让读者进入,它就会让所有等待的读者同时进入,即使有些人“在”其他等待的作者之后出现。
- 在“EndWrite”代码中(它在不检查等待写入者的情况下向 CanWrite 发出信号)
- 在 EndRead 代码中(同样的事情)
- 在 StartRead 中(最后发出 CanRead 信号)
With Semaphores we never did have a “fair” solution of this sort. In fact it can be done but the code is quite tricky. Here the straightforward solution works in the desired way! Monitors are less error-prone and also easier to understand.