Thread Synchronization lock, Monitor, Interlocked
I've been reading a lot about thread synchronization to understand the lower-level intracacies of how the .NET framework handles threading issues. Most of you may be most familiar with the lock() statement and use it pretty loosely.
- But what's really happening under the hood?
- What are some threading alternatives?
- What is System.Threading.Monitor?
- What about System.Threading.Interlocked?
Well, under the hood, a lock function, ie,
lock(something)
{
// do work
}
is actually performing this:
object tmpObject = synchHandle;
System.Threading.Monitor.Enter(tmpObject);
try
{
total++;
}
finally
{
System.Threading.Monitor.Exit(tmpObject);
}
But, then they have a neat little function for timeouts. Say you have a resource that you need to access with thread safety. But that function hangs. You cannot release the lock. Now you have a dealock, and nothing else can access that function until it is released. That is why you have the Monitor.TryEnter function which has a timeout feature.
if (!Monitor.TryEnter(syncHandle, 1000)) // wait 1 second
throw new PreciousResourceException
("Could not enter critical section");
try
{
total++;
}
finally
{
Monitor.Exit(syncHandle);
}
The article I was reading had a neat little way of wrapping it all up into this neat little functionality.
public sealed class LockHolder<T> : IDisposable where T : class
{
private T handle;
private bool holdsLock;
public LockHolder(T handle, int milliSecondTimeout)
{
this.handle = handle;
holdsLock = System.Threading.Monitor.TryEnter(
handle, milliSecondTimeout);
}
public bool LockSuccessful
{
get { return holdsLock; }
}
#region IDisposable Members
public void Dispose()
{
if (holdsLock)
System.Threading.Monitor.Exit(handle);
// Don’t unlock twice
holdsLock = false;
}
#endregion
}
And now you can wrap it all up nicely with reusability as such:
using (LockHolder<object> lockObj = new LockHolder<object>
(lockHandle, 1000))
{
if (lockObj.LockSuccessful)
{
// work elided
}
}
Interlocking is for manipulating objects safely such as incrementing. In the words of Bill Wagner:
For most common synchronization problems, examine the Interlocked class to see if it can be used to provide the capabilities you need. With many single operations, it can. When it can’t your first choice is the lock() statement. Only look beyond those when you need some special purpose locking capability.
For more information about Interlocked.Decrement() and Interlocked.Decrement()and Interlocked.Exchange() functions. The Pulse and Wait methods to implement a consumer / producer design. And more about the ReaderWriterLockSlim class, read the article at:
http://www.informit.com/articles/article.aspx?p=1231461
Friday, May 08, 2009 2:23:51 PM