Question

In Monitor documentation of .NET Framework 4.5 I found a sentence, which says that lock keyword uses Enter(Object, Boolean) method of Monitor:

The functionality provided by the Enter and Exit methods is identical to that provided by the C# lock statement (SyncLock in Visual Basic), except that lock and SyncLock wrap the Enter(Object, Boolean) method overload and the Exit method in a try…finally block (Try…Finally in Visual Basic) to ensure that the monitor is released.

On the other hand in the overwiew of Monitors there is:

The Visual Basic SyncLock and C# lock statements use MonitorEnter to take the lock and MonitorExit to release it.

MonitorEnter in above refers to different version of Enter method than previous, namely: Enter(Object)

In Thread Synchronization (C# and Visual Basic) for Visual Studio 2012 there is a sample how lock wraps Monitor:

System.Object obj = (System.Object)x;
System.Threading.Monitor.Enter(obj);
try
{
    DoSomething();
}
finally
{
    System.Threading.Monitor.Exit(obj);
}

There is also Enter(Object) version.

What is true? Does lock statement calls Enter(Object, Boolean) or Enter(Object)? Whether there is any difference how it is really done?

Was it helpful?

Solution

From Eric Lippert’s Blog:

Recall that lock(obj){body} was [in C# 3.0 and earlier] a syntactic sugar for

var temp = obj;
Monitor.Enter(temp);
try { body }
finally { Monitor.Exit(temp); }

The problem here is that if the compiler generates a no-op instruction between the monitor enter and the try-protected region then it is possible for the runtime to throw a thread abort exception after the monitor enter but before the try. In that scenario, the finally never runs so the lock leaks, probably eventually deadlocking the program. It would be nice if this were impossible in unoptimized and optimized builds.

In C# 4.0 we've changed lock so that it now generates code as if it were

bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }

The problem now becomes someone else's problem; the implementation of Monitor.Enter takes on responsibility for atomically setting the flag in a manner that is immune to thread abort exceptions messing it up.

So everything is good now, right?

Sadly, no. [...]

On the other hand, the C# 4.0 Language Specification says:

A lock statement of the form

lock (x) ...

where x is an expression of a reference-type, is precisely equivalent to

System.Threading.Monitor.Enter(x);
try {
   ...
}
finally {
   System.Threading.Monitor.Exit(x);
}

except that x is only evaluated once.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top