Being Cellfish

Stuff I wished I've found in some blog (and sometimes did)

Repetitive Lazy<T> to the rescue

Change of Address
This blog has moved to blog.cellfish.se.

Repetitive Lazy<T> to the rescue

  • Comments 2

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.

  • Why not just box it? This way you're still able to rely on the atomic assignment of a reference, and you're probably saving an allocation or two depending on the internals of Lazy<T> (at least 1 allocation is saved due to the lambda). It does add a cast and unbox to the mix, but probably cheaper than Lazy<T> (if you really need to know if it's faster/slower, measure it!).

    private object theValue = (object)default(int);

    public int UseTheValue() { int valueToUse = (int)theValue; ...; return valueToUse; }

    public void SetTheValue(int value) { theValue = (object)value; }

    Boxing gets a bad rep, and rightly so, but on occasion it's quite handy and may be the simplest solution :) You could also easily come up with your own BoxedValue<T> class and avoid the cast, and improve static type safety, and I don't believe it'd be any more memory usage than implicit boxing.

    In any event, good idea ... I realized I hadn't even been thinking about struct tearing in awhile for things like this. I may have some code to go inspect ...

  • Interesting idea to use boxing! Just didn't occur to me at first.

Page 1 of 1 (2 items)