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.