Introduction
I'm guessing plenty of people have already done this themselves. But if you haven't written Read/Write extensions for ReadWriterLockSlim
(or any other lock class), here you go.
Background
I found myself writing the following pattern way too often:
bool lockHeld = false;
try
{
lockHeld = rwlock.EnterReadLock();
closure();
}
finally
{
if (lockHeld)
rwlock.ExitReadLock();
}
I also found myself needing a way to enter locks with timeouts in the same way. So I started by making the following extension:
public static bool EnterReadLock(this ReaderWriterLockSlim target,
int? millisecondsTimeout, bool throwsOnTimeout = false)
{
if (millisecondsTimeout == null)
target.EnterReadLock();
else if (!target.TryEnterReadLock(millisecondsTimeout.Value))
{
if (throwsOnTimeout)
throw new TimeoutException(
"Could not gain a read lock within the timeout specified. " +
"(millisecondsTimeout=" + millisecondsTimeout.Value + ") ");
return false;
}
return true;
}
Which led me to write a set of extensions that look like this:
public static bool Read(this ReaderWriterLockSlim target,
Action closure, int? millisecondsTimeout = null, bool throwsOnTimeout = false)
{
Contract.Requires<ArgumentNullException>(closure != null);
Contract.Requires<ArgumentOutOfRangeException>(
millisecondsTimeout == null || millisecondsTimeout >= 0
);
bool lockHeld = false;
try
{
lockHeld = target.EnterReadLock(millisecondsTimeout, throwsOnTimeout);
closure();
}
finally
{
if (lockHeld)
target.ExitReadLock();
}
return lockHeld;
}
Resulting in some very flexible and robust delegated extensions.
Usage Examples
Can't be much easier than:
rwlock.Read( ()=> { } );
if( !rwlock.Read( ()=> { }, 1000 ) )
{
}
int myValue = rwlock.ReadValue( ()=>
{
int value;
return value;
} );
rwlock.ReadUpgradable( ()=>
{
if(needsWrite()) { rwlock.Write(()=>{
}
}
}
Download the code for more useful extensions.