问题
The msdn article Thread Synchronization (C# Programming Guide) specifies that:
lock (x)
{
DoSomething();
}
is equivalent to:
System.Object obj = (System.Object)x;
System.Threading.Monitor.Enter(obj);
try
{
DoSomething();
}
finally
{
System.Threading.Monitor.Exit(obj);
}
and then that:
"Using the lock keyword is generally preferred over using the Monitor class directly, ... because lock insures that the underlying monitor is released, even if the protected code throws an exception"
Does this phrase mean that the last code snippet, using the monitor, does not insure that "the underlying monitor is released, even if the protected code throws an exception" ?
And why?
Well, I am confused by the contradicting each other assertions "equivalent" and not (one usage insures and another, equivalent, does not) about the same.
回答1:
If you have a look at the IL that is generated by the 4.0 compiler for anycpu and reverse that to C# the clossest lock equivelent implementation I could get at would look like:
object x = new object();
bool lockTaken = false;
// lock
try{
System.Threading.Monitor.Enter(x, ref lockTaken)
DoSomeThing();
}
finally
{
if (lockTaken)
{
System.Threading.Monitor.Exit(x);
}
}
All is done to prevent the situation where a lock is taken, a thread aborts and the lock is never released, causing a race/deadlock. The warning tells you basically to balance Enter and Exit calls in good and formost failure situations. The lock statement is the simplest abstraction that achieves that goal.
Based on this IL:
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
.try
{
IL_0003: ldsfld object p::x
IL_0008: dup
IL_0009: stloc.1
IL_000a: ldloca.s 0
IL_000c: call void [mscorlib]System.Threading.Monitor::Enter(object, bool&)
IL_0011: nop
IL_0012: nop
IL_0013: call void p::DoSomething()
IL_0018: nop
IL_0019: nop
IL_001a: leave.s IL_002c
} // end .try
finally
{
IL_001c: ldloc.0
IL_001d: ldc.i4.0
IL_001e: ceq
IL_0020: stloc.2
IL_0021: ldloc.2
IL_0022: brtrue.s IL_002b
IL_0024: ldloc.1
IL_0025: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_002a: nop
IL_002b: endfinally
} // end handler
IL_002c: nop
IL_002d: ldsfld object p::x
IL_0032: call void [mscorlib]System.Threading.Monitor::Enter(object)
IL_0037: nop
.try
{
IL_0038: nop
IL_0039: call void p::DoSomething()
IL_003e: nop
IL_003f: nop
IL_0040: leave.s IL_0050
} // end .try
finally
{
IL_0042: nop
IL_0043: ldsfld object p::x
IL_0048: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_004d: nop
IL_004e: nop
IL_004f: endfinally
} // end handler
IL_0050: nop
IL_0051: ret
回答2:
The case that the bolded text refers to is something more like this:
Monitor.Enter(obj);
DoSomethingThatThrows();
Monitor.Exit(obj);
where, without the try-finally, throwing the exception will bypass the Monitor.Exit
call.
回答3:
If lock is functionally equivalent to the bit of code provided, both obviously ensure that it will be released, as there's a finally clause. However, if you just use monitor without finally, you can run into trouble, causing a deadlock.
At least, that's what I believe the article means by its explanation.
回答4:
On x64 architectures (Up until the VS2008 JIT according to J.Duffy - in some corner cases it still happens, when compiling for Any CPU
without /o+
switch.) it was possible that an IL instruction was put between the Monitor.Enter
and the Try
statements. If an exception happened when the stack pointer was at this instruction, the lock
would never be released.
The code generation for the lock
keyword however prevented this from happening.
Thats probably why they suggest using the lock
keyword.
References:
Monitor.Enter, Thread aborts
回答5:
It means that when you use the Monitor you might forget to use the try-finally.
Actually you'll encounter that alot of people just use Monitor.Enter in the beginning of a block and Monitor.Exit in the end of the block.
That doesn't promise the Monitor.Exit to happen, because an exception can cause the code to stop running in the middle of the block.
来源:https://stackoverflow.com/questions/15020064/why-does-the-lock-insure-that-the-underlying-monitor-is-released-and-direct-usag