- 下载源代码 - 1.4 KB
标准Monitor.Wait和Monitor.PulseAll方法现在很少使用,但仍然可以提供强大的线程同步能力。如前所述,我们将实现一个标准的读写器锁,所以让我们直接深入代码:
private readonly object syncRoot = new object();
private readonly object syncWrite = new object();
// A number of acive readers.
private int rcount = 0;
// A total number of pending and active writers.
private int wcount = 0;
没错,我们只需要两个计数器——一个用于每个所有者类型,两个用于同步的根对象。接下来,让我们探索EnterXXXLock部分:
public void EnterReadLock()
{
lock (syncRoot)
{
while (wcount > 0)
{
Monitor.Wait(syncRoot); // Wait till all writers are done.
}
rcount++; // Notify that there is an active reader.
}
}
public void EnterWriteLock()
{
lock (syncRoot)
{
wcount++; // Notify that there is a pending writer.
while (rcount > 0)
{
Monitor.Wait(syncRoot); // Wait till all readers are done.
}
}
Monitor.Enter(syncWrite);
}
该EnterReadLock方法仅允许读者在reader未访问资源时继续。反过来,该EnterWriteLock方法会立即通知writer的存在,然后等待reader释放锁。从技术上讲,这段代码将传入的请求分成两大组writer和reader,前者优先。因此,我们需要一个额外的调用Monitor.Enter(syncWrite)来确保在给定的时间只有一个writer可以访问。以下发布逻辑:
public void ExitReadLock()
{
lock (syncRoot)
{
if (--rcount == 0 && wcount > 0)
{
Monitor.PulseAll(syncRoot); // Notify writers waiting.
}
}
}
public void ExitWriteLock()
{
Monitor.Exit(syncWrite);
lock (syncRoot)
{
if (--wcount == 0)
{
Monitor.PulseAll(syncRoot); // Notify readers waiting.
}
}
}
连续的最后一个reader或writer只是唤醒所有等待的线程,以便他们可以继续比赛。为了演示这是如何工作的,我创建了一个控制台应用程序,它运行多个线程同时访问同一资源。这是应用程序生成的示例输出:
源代码可在此链接下载。只需解压缩并执行dotnet run命令即可。
https://www.codeproject.com/Tips/5323262/The-Simplest-Implementation-of-a-Reader-Writer-Loc