Threading – Using ReaderWriterLockSlim

When dealing with concurrency/threading issues in .Net, the normal approach is to use lock() to lock a dedicated sync object like this:

private static readonly object padlock = new object();
…
lock(padlock)
{
     // enter critical section here
}

This is an efficient, simple and well proven way to get thread-safety in .Net and is probably all you’ll ever need in your project. However, as this approach ensures only one thread can enter the critical section at any one time it’s not ideal for managing access to a shared resource because all read and write operations must be made sequentially and this results in a performance hit on your application. Ideally all threads should be able to read the shared resource simultaneously but only one thread can update it and no other threads can read from the resource whilst the update is happening.

.Net’s answer to this used to be the ReaderWriterLock, which since .Net 3.5 has been superseded by the better, more lightweight and performing ReaderWriterLockSlim which Microsoft is recommending for all new development.

The ReaderWriterLockSlim has three modes: Read, Ungradeable and Write:

  • many threads can enter Read lock simultaneously
  • only one thread can enter Ungradeable lock but other threads can still enter Read lock
  • only one thread can enter Write lock and no other thread can enter any lock

In practice though, almost all threading problems can be solved using read and write locks alone. To enter read/write lock, you need something like this:

private static readonly ReaderWriteLockSlim rwlock = new ReaderWriterLockSlim();
…
rwlock.EnterReadLock()
try
{
     // do something here
}
finally
{
     // don't forget to release the lock afterwards!
     rwlock.ExitReadLock();
}

As you can see, this can seriously clutter your code if you require read/write locks in many places! I saw this post on StackOverflow quite some time back and really like the pattern that Marc has presented:

http://stackoverflow.com/questions/170028/how-would-you-simplfy-entering-and-exiting-a-readerwriterlock

In his answer he showed how you can simplify the code needed to enter a read lock, here’s the full implementation you can use in your project:

public static class ReaderWriterLockSlimExtensions
{
     private sealed class ReadLockToken : IDisposable
     {
          private ReaderWriterLockSlim _sync;
          public ReadLockToken(ReaderWriterLockSlim sync)
          {
               _sync = sync;
               sync.EnterReadLock();
          }
          public void Dispose()
          {
               if (_sync != null)
               {
                    _sync.ExitReadLock();
                    _sync = null;
               }
          }
     }
     private sealed class WriteLockToken : IDisposable
     {
          private ReaderWriterLockSlim _sync;
          public WriteLockToken(ReaderWriterLockSlim sync)
          {
               _sync = sync;
               sync.EnterWriteLock();
          }
          public void Dispose()
          {
               if (_sync != null)
               {
                    _sync.ExitWriteLock();
                    _sync = null;
               }
          }
     }

     public static IDisposable Read(this ReaderWriterLockSlim obj)
     {
          return new ReadLockToken(obj);
     }
     public static IDisposable Write(this ReaderWriterLockSlim obj)
     {
          return new WriteLockToken(obj);
     }
}

And to use it in your code, this is all you’ll need:

using (_sync.Read())
{
     // do reading here
}
using (_sync.Write())
{
     // do writing here
}

Further Readings:

Jon Skeet’s tutorial on Multi-Threading in .Net

Ayande has a post on using the UpgradeableReadLock

  • http://www.emo--boys.info Invintyinpurn

    i easily love your own posting choice, very remarkable.
    don’t give up as well as keep creating simply because it simply very well worth to follow it.
    impatient to browse a whole lot more of your current article content, good bye ;)

  • Nicolas

    I was looking for something like this.
    Check the comment of Steven: http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/

    As he explained, acquiring the lock inside the using statement can be problematic.