I found the book Java Concurrency in Practice to be an excellent guide to writing multithreaded code for Java. I am wondering to what extent the general principals described in the book apply to .Net. I am not interested in rolling my own lock free code – I just want to use solid, understandable techniques and exploit existing synchronized and concurrent APIs. To that extent, the key takeaways from the book for me were:
- Locking – states changes made inside a lock in one thread are visible to all other threads inside a locks on the same object. No doubt this works in .NET and would be sufficient to write thread safe programs but it leads to unnecessary locking if we cannot rely on the following mechanisms.
- Safe Publication – The latest state of an effectively immutable object (an object which is not changed after publication) is visible to all threads provided one of the following holds. Note that seeing the latest state of a reference to an object is not the necessarily same as seeing the latest state of the object itself – in Java safe publication works because of the transitive nature of the happens-before relationship.
- Access to it’s references are synchronized via locks in all threads
- It is referenced via a volatile variable
- It is published from a synchronized or concurrent collection.
- The latest state of properly constructed immutable objects with only final fields (readonly in .NET) are thread safe regardless of how they are published.
I would hope all of these work otherwise it makes life unnecessarily difficult, but from what I have ready the model for .Net (at least as it is specified) is quite weak. Has anyone tried to construct a happens-before model for .NET? I think this an area which badly needs to be addressed in .Net. As far as I know there isn’t an equivalent book for .Net which can give the same ‘level of comfort’ – it seems that at least part of the problem is the lack of a well defined memory model for .NET.
The general concepts are the same. The differences between the Java and .NET memory model need to be taken into account though. This usually involves using the Interlocked functions (in Java), VolatileRead / VolatileWrite or explicit memory barrier.
There are two memory models specified for .NET. A weak memory model specified in Section 12, Partition I of the .NET Framework ECMA standard. Stronger memory model is actually implemented by the .NET Framework runtime. An alternative definition is described by Joe Duffy. One practical case where the .NET memory model makes difference to Java one is described on the IKVM.NET blog.
Regarding your points:
Locking works the same way as in Java.
Safe publication – The first two scenarios (locks and volatile) work identical to the Java counterparts.
Synchronized collections in .NET are deprecated, but they internally use a lock, so they work exactly the same way as if the accesses were locked.
Concurrent collections added as part of .NET 3.5 internally use lock-free techniques, so they should be memory coherent between different threads. I’m not sure if they are memory consistent though.