Here is a fast reader/writer updated from Birrell's of MSR. Accounts for
writer starvation:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Locks
{
/// <summary>
/// Condition Variable (CV) class.
/// </summary>
public class CV
{
private readonly object syncLock = new object(); // Internal lock.
private readonly object m; // The lock
associated with this CV.
public CV(object m)
{
lock ( syncLock )
{
this.m = m;
}
}
public void Wait()
{
bool enter = false;
try
{
lock ( syncLock )
{
Monitor.Exit(m);
enter = true;
Monitor.Wait(syncLock);
}
}
finally
{
if ( enter )
Monitor.Enter(m);
}
}
public void Pulse()
{
lock ( syncLock )
{
Monitor.Pulse(syncLock);
}
}
public void PulseAll()
{
lock ( syncLock )
{
Monitor.PulseAll(syncLock);
}
}
}
public sealed class RW
{
private readonly object syncRoot = new object(); // Internal
lock.
private int i = 0; // 0 or greater
means readers can pass; -1 is active writer.
private int readWaiters = 0; // Readers
waiting for writer to exit.
private int writeWaiters = 0; // Writers
waiting for writer lock.
private CV wQ; // Condition
variable.
public RW()
{
wQ = new CV(syncRoot);
}
/// <summary>
/// Gets a value indicating if a reader lock is held.
/// </summary>
public bool IsReaderLockHeld
{
get
{
lock ( syncRoot )
{
if ( i > 0 )
return true;
return false;
}
}
}
/// <summary>
/// Gets a value indicating if the writer lock is held.
/// </summary>
public bool IsWriterLockHeld
{
get
{
lock ( syncRoot )
{
if ( i < 0 )
return true;
return false;
}
}
}
/// <summary>
/// Aquires the writer lock.
/// </summary>
public void AcquireWriterLock()
{
lock ( syncRoot )
{
writeWaiters++;
while ( i != 0 )
wQ.Wait(); // Wait until existing writer frees the
lock.
writeWaiters--;
i = -1; // Thread has writer lock.
}
}
/// <summary>
/// Aquires a reader lock.
/// </summary>
public void AcquireReaderLock()
{
lock ( syncRoot )
{
readWaiters++;
// Defer to a writer (one time only) if one is waiting to
prevent writer starvation.
if ( writeWaiters > 0 )
{
wQ.Pulse();
Monitor.Wait(syncRoot);
}
while ( i < 0 )
Monitor.Wait(syncRoot);
readWaiters--;
i++;
}
}
/// <summary>
/// Releases the writer lock.
/// </summary>
public void ReleaseWriterLock()
{
bool doPulse = false;
lock ( syncRoot )
{
i = 0;
// Decide if we pulse a writer or readers.
if ( readWaiters > 0 )
{
Monitor.PulseAll(syncRoot); // If multiple readers
waiting, pulse them all.
}
else
{
doPulse = true;
}
}
if ( doPulse )
wQ.Pulse(); // Pulse one writer if one
waiting.
}
/// <summary>
/// Releases a reader lock.
/// </summary>
public void ReleaseReaderLock()
{
bool doPulse = false;
lock ( syncRoot )
{
i--;
if ( i == 0 )
doPulse = true;
}
if ( doPulse )
wQ.Pulse(); // Pulse one writer if one
waiting.
}
} // RW
}
By the way, when is Microsoft going to be broken up so that we developers
and consumers can actually get worthwhile products in a timely manner?
I assume your kidding.
Cheers.