When deal­ing with concurrency/threading issues in .Net, the nor­mal approach is to use lock() to lock a ded­i­cated sync object like this:

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

This is an effi­cient, sim­ple and well proven way to get thread-safety in .Net and is prob­a­bly all you’ll ever need in your project. How­ever, as this approach ensures only one thread can enter the crit­i­cal sec­tion at any one time it’s not ideal for man­ag­ing access to a shared resource because all read and write oper­a­tions must be made sequen­tially and this results in a per­for­mance hit on your appli­ca­tion. Ide­ally all threads should be able to read the shared resource simul­ta­ne­ously 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 Read­er­Writer­Lock, which since .Net 3.5 has been super­seded by the bet­ter, more light­weight and per­form­ing Read­er­Writer­Lock­Slim which Microsoft is rec­om­mend­ing for all new development.

The Read­er­Writer­Lock­Slim has three modes: Read, Ungrade­able and Write:

  • many threads can enter Read lock simultaneously
  • only one thread can enter Ungrade­able 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 prac­tice though, almost all thread­ing prob­lems can be solved using read and write locks alone. To enter read/write lock, you need some­thing 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 seri­ously clut­ter your code if you require read/write locks in many places! I saw this post on Stack­Over­flow quite some time back and really like the pat­tern 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 sim­plify the code needed to enter a read lock, here’s the full imple­men­ta­tion 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
}

Fur­ther Readings:

Jon Skeet’s tuto­r­ial on Multi-Threading in .Net

Ayande has a post on using the UpgradeableReadLock

Share
  • http://www.emo--boys.info Invin­ty­in­purn

    i eas­ily love your own post­ing choice, very remark­able.
    don’t give up as well as keep cre­at­ing sim­ply because it sim­ply very well worth to fol­low it.
    impa­tient to browse a whole lot more of your cur­rent arti­cle con­tent, good bye ;)

  • Nico­las

    I was look­ing for some­thing like this.
    Check the com­ment of Steven: http://thevalerios.net/matt/2008/09/using-readerwriterlockslim/

    As he explained, acquir­ing the lock inside the using state­ment can be problematic.