Tuesday, August 2, 2011

Enforcing your object to be thread safe

Hi everyone, after a long time that i didn't write because i was on a long vacation, i wanted to share a very cool and simple code for enforcing thread safe calls to an object.

The motive was a lot of race conditions and deadlocks that happened to my team members so i found a solution for them by enforcing all the reading and writing to our model to be thread safe.
This is how i implemented it:

using System;
using System.Threading;
namespace MyCode {
   
   public class ThreadSafeObject<T>{
      private readonly ReaderWriterLockSlim _rwLock;
      private T _value;

      public ThreadSafeObject(T value){
         _rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
         _value = value;
      }

      public void SafeRead(Action<T> readFunction){
         try{
            _rwLock.EnterReadLock();
            readFunction.Invoke(_value);
         }
         finally{
            _rwLock.ExitReadLock();
         }
      }

      public void SafeWrite(Action<T> writeFunction){
         try{
            _rwLock.EnterWriteLock();
            writeFunction.Invoke(_value);
         }
         finally{
            _rwLock.ExitWriteLock();
         }
      }
   }
}

So as you can see, any access to my model (T) must go through a loch (read or write).

In our team, the T also implements an 'Observable' pattern so if a 'write' action is made inside read lock i actually throw 'IllegalOperationException' and also enforce that no write is performed in read lock.

Here is some code example of how to use it:

namespace MyCode {
    class Model {
      public int IntValue { get; set; }
      public string StringValue { get; set; }
   }

   class Example {
      public void ThreadSafeExample() {
         var threadSafeObject = new ThreadSafeObject<Model>(new Model());

         /// Writing values in a safe single transaction
         threadSafeObject.SafeWrite(state => {
            state.IntValue = 100;
            state.StringValue = "This is very cool design!!";
         });

         /// Reading values in a safe way (allow also multiple readers)
         var intValueRead = 0;
         var stringValueRead = string.Empty;
         var readingTime = DateTime.MinValue;
         threadSafeObject.SafeRead(state => {
            readingTime = DateTime.Now;
            intValueRead = state.IntValue;
            stringValueRead = state.StringValue;
         });

         Console.WriteLine("At {0} the model had in value of {1} and string value of: {2}", readingTime, intValueRead, stringValueRead);
      }
   }
}


This is it...

I hope it will be helpful for you as it was for me.

Gur

2 comments:

  1. Thanks for sharing the code.I was also facing a similar situation and was looking out for solution.enforcing thread safe calls is really important for avoiding deadlocks.I am going to try this code and will update you on results.
    electronic signature for sharepoint

    ReplyDelete