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.