IS AllStars Login
Keywords
Location

.NET Thread Sync with lock(), Monitor, and Interlocked functions


Blog Date: 5/8/2009
 

Recent Blogs

<< Back

ASP.NET MVC versus Web Forms vs Silverlight 4/21/2009
Unit Testing with Dependency Injection 4/25/2009
ASP.NET HttpHandlers and HttpModules 5/5/2009
 More Blogs...

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



5/8/2009 2:23:51 PM
Home | Job Search | Career Tools | Blog | Tech News | Contact | Site Map