Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / threads

ReaderWriterLockSlim Extensions

0.00/5 (No votes)
13 Feb 2013CPOL 10.1K   95  
Make your synchronizion easier by using Read/Write extensions.

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:
C++
rwlock.Read( ()=> { /* Some read operation */ } ); 
C++
if( !rwlock.Read( ()=> { /* Some read operation */ }, 1000 ) )
{ // Was unable to get a read lock within 1 second?
  /* Do something else */
}
C++
int myValue = rwlock.ReadValue( ()=>
{
  int value;
  /* Get the value */
  return value;
} );
C++
rwlock.ReadUpgradable( ()=>
{
    if(needsWrite()) { // Do verification before writing...
         rwlock.Write(()=>{
             /* Do write operation */
         }
    }
}

Download the code for more useful extensions.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)