Threading Tips: Never Lock a Value Type. Never Lock "This".

UPDATE: As a commenter pointed out, the original code example did not properly demonstrate the problem with locking on the this keyword within a normal method. I have corrected this example and wrote a better example that demonstrates that this problem still exists even in a “normal” method.

Take a look at this code:

private bool isDisposed = false;
 
//... code...
~MyClass()
{
    lock(isDisposed)
    {
        if(!isDisposed)
        {
            //Do Stuff...
        }
    }
}

Hopefully you can see the problem here right away. The lock statement takes an object instance as a parameter. So what happens to the boolean isDisposed within the lock statement? That’s right! It gets boxed, meaning a new object instance is allocated and passed to the lock statement. Thus every time you lock on a value type, you’re locking on a new object.

Ok, so let’s try to fix this up a bit.

private bool isDisposed = false;
 
//... code...
~MyClass()
{
    lock(this)
    {
        if(!isDisposed)
        {
            //Do Stuff...
        }
    }
}

So is there anything wrong with this? You’ve probably seen the Microsoft examples locking on this. Well never give full trust to example code (especially as it’s unlikely you’ll add the code to the GAC) ;). Suppose this snippet is from a class MyClass. What do you think will happen with the following code:

MyClass instance = new MyClass();

Monitor.Enter(instance);
instance = null;

GC.Collect();
GC.WaitForPendingFinalizers();

You guessed it! Deadlock.

Every time you lock a .NET object, the runtime associates a SyncBlock structure to that object. Locking works by checking who owns an object’s SyncBlock when attempting to acquire a lock. Thus in the code sample above, the client code and the Dispose() Method are attempting to lock on the same object.

For a more in-depth discussion, I highly recommend Jeffrey Richter’s article Safe Thread Synchronization which is where I first learned about this subtle threading issue.

Likewise you might also take a look at Dr Gui’s Don’t Lock Type Objects post.

Technorati Tags: ,

What others have said

Requesting Gravatar... Barry Dorrans Apr 12, 2005 10:37 AM
# re: Threading Tips: Never Lock a Value Type. Never Lock "This".
*hanging head in shame now*

:)
Requesting Gravatar... jayson knight Apr 12, 2005 5:03 PM
# re: Threading Tips: Never Lock a Value Type. Never Lock "This".
I remember reading somewhere (some blog) that the CLR folks didn't really want to have a lock keyword, but by the time they realized how evil it was, it was too late.

Something I've always wanted to test (but haven't gotten around to it, or I forget) is locking a shallow copy of an object...would that work? As it creates a proxy back to the original object, I would think it would...

good post.
Requesting Gravatar... Haacked Apr 12, 2005 5:55 PM
# re: Threading Tips: Never Lock a Value Type. Never Lock "This".
You might have read that on this blog in a post entitled "The Difficulties of Language Design"

http://haacked.com/archive/2004/05/27/492.aspx
Requesting Gravatar... Daniel Moth Apr 17, 2005 10:43 AM
# re: Threading Tips: Never Lock a Value Type. Never Lock "This".
Similar problems occur when locking on strings (don't!) because of interning...
Requesting Gravatar... Jack Aug 08, 2006 10:09 AM
# re: Threading Tips: Never Lock a Value Type. Never Lock "This".
A late comment, since this is still generating bad memes:

You seem to be implying that multiple locks on the same object from the same thread, will cause deadlock, which is just wrong. Maybe its possible that your example can cause deadlock because it's called from Dispose and that's deadlocking with the GC thread, but I don't see quite how (if it were a destructor, I might believe you). In any case, locking on "this" in an ordinary method is fine.

Requesting Gravatar... Haacked Aug 08, 2006 11:28 AM
# re: Threading Tips: Never Lock a Value Type. Never Lock "This".
@Jack: Whoops, you are right. That should be the finalizer method, not dispose. My code example is not illustrating the point correctly.

However, the point remains. Locking on "this" in an ordinary method can still cause contention with some external thread locking on the object since they will both lock on the same synch block.

Read Richter's article on the subject. I'll post a correction to this post.
Requesting Gravatar... Abhinav Oct 03, 2008 8:01 PM
# re: Threading Tips: Never Lock a Value Type. Never Lock "This".
I never see Lock(valueType) getting compiled.May I know what am i missing?

What do you have to say?

(will show your gravatar)
Please add 7 and 5 and type the answer here: