Freigeben über


Repetitive Lazy to the rescue

The other day I was doing my usual double check locking when a co-worker pointed out that without a memory barrier the typical implementation is not necessarily safe. It is described here together with several options from a singleton perspective. Also my time on the Robotics team have made me almost religious about trying to avoid any kind of manual synchronization (i.e. when I use a synchronization object explicitly in my code). The problem I was trying to fix this time involved one method that runs for a relatively long time. During this time a property must not change. Easy enough to get around I thought and made the type of the property a struct (I could have made the class IClonable too, but since the object consist only of a number of value types a struct made sense to me.

Since assignment of structs are not atomic I needed something to make sure the struct being copied did not change at the same time resulting in a corrupt struct. Nor could I take a lock for the whole execution of this method since any thread needing to change this property would need to do so quickly without waiting for the long running method. I realized that I could use the Lazy<T> to not create my own lock and make the code look really nice. This is the essence of what I came up with:

   1: public class RepetitiveLazyUsage
  2: {
  3:     private Lazy<int> theValue = 
  4:         new Lazy<int>(LazyThreadSafetyMode.ExecutionAndPublication); 
  5:  
  6:     public int UseTheValue()
  7:     {
  8:         int valueToUse = theValue.Value;
  9:         // Relativly slow code here that depends on valueToUse.
 10:         return valueToUse;
 11:     }
 12:  
 13:     public void SetTheValue(int value)
 14:     {
 15:         theValue = new Lazy<int>(
 16:             () => value, 
 17:             LazyThreadSafetyMode.ExecutionAndPublication);
 18:     }
 19: }

As you can see this looks pretty nice I think and I'm using two features to make sure this code does not have any problems in a multi-threaded environment. First I use Lazy<T> in a thread-safe mode and that way I don't need an explicit lock. Second I use the fact that reference type assignments are atomic in .Net and hence replacing the instance of theValue in the SetNewValue method does not need a lock nor when I'm getting the value.

Comments

  • Anonymous
    January 31, 2012
    The comment has been removed
  • Anonymous
    January 31, 2012
    Interesting idea to use boxing! Just didn't occur to me at first.