The Art of Thread Synchronization
I attended a NETDA lecture by Jeffrey Richter on Monday, in which spoke on “The Art Of Thread Synchronization.” Last year, Jeffrey talked about new Platform vs Library versioning features in Orcas and Longhorn, the contents of which is mentioned in a prior post.
Jeffrey Richter is co-founder of Wintellect, a well-known training and consulting firm. He wrote Applied Microsoft .NET Framework Programming, which is a must have for advanced .NET developers. He is a contributing editor at MSDN Magazine and also consults with both the Microsoft .NET Framework team and the Indigo team.
He reviewed the variety of threading mechanisms in .NET, and demonstrated how one could implement some of the same locks in handwritten code, superior to the versions included in the framework in both performance (eliminating kernel mode transitions), correctness, and fairness (locks are served in FIFO order). He made clear that many of the System.Threading classes are not very optimized or optimal in their performance. He reimplemented a SpinLock, an Optex lock, a ReaderWriterLock and a few others. He also showed how one could write Interlocked versions of other operations such as the bitwise AND operator.
Some problems in the framework include the following:
- Whidbey includes Int64 versions of CompareExchange, Exchange, Increment and Add in the Interlocked class. Unfortunately, these functions can’t be guaranteed to work on a 32–bit processor, and thus shouldn’t really be included in the framework.
- ReaderWriterLock has a very serious flaw, which prevented its use in MSN website, because it could lead to starvation for writers, if too many readers are using the lock. Richter produced a superior ReaderWriterLock implementation, that both performs better and gives priority to writers to eliminate starvation; this new lock will be included in the Orcas version of the framework
- Many of the framework’s locks perform poorly because of excessive kernel mode transitions. He showed benchmark results, which demonstrated an order of magnitude or two deterioration in performance due to kernel mode transitions alone. For the fastest performance, a developer should rely only on the methods on the Interlocked class, which neither waits nor transitions to kernel mode. Locks should be designed to call into the kernel only during contention, which can be checked for by using Interlocked.CompareExchange.
Jeffrey invented a super-fast thread synchronization lock, SoaReaderWriterLock, that never puts any thread in a wait state. He applied for a patent and sold the idea to Microsoft. Richter urged Microsoft to relax restrictions to the use of the lock. Microsoft agreed to allow the technique to developers of Windows application but not other platforms like Linux.
His description of the lock was very impressive. The lock mechanism works differently from traditionally block schemes which rely on the try-finally mechanism. It is based on Service Oriented Architecture, in which methods are called in a “Fire and Forget” manner. A delegate is first passed to a Lock when it is first entered. The delegate is either service immediately or sent to a reader or writers queue, where it will later be dispatched to a threadpool. In effect, the application becomes the scheduler instead of the operation system: After one delegate executes, the next available one is called immediately without any intermediate wait state.
The Wintellect site currently contains the PowerCollections library, which works only on Whidbey, but Jeffrey Richter will soon be adding a PowerThreading library as well to correct for the deficiencies in the .NET Framework. The SOA lock will also be included with the aforementioned restrictions.
After the talk, I spoke to Richter about his prior versioning talk, and he mentioned that there was a lot of pushback from groups all over Microsoft and that the versioning strategy will not survive as originally planned. Software development apparently is a fluid process.