We have experience some weird deadlock using managed code.

We have a class with some shared resources. To protect the shared resources, we create a synchronization object, and use Lock(object) prior to access the shared resources. There is no nested lock so in theory we should never have deadlock.

However, for some reason, one of the call has stucked in the Lock(object) call.

After a round of discussion with CLR team, we finally figure out the problem.

It is a debug build. (not surprising given we are in development.) The C# compiler generates the following code for Lock(object) in debug mode.

IL_0039: ldarg.0

IL_003a: ldfld stateLock

IL_003f: dup

IL_0040: stloc.3

IL_0041: call System.Threading.Monitor::Enter

IL_0046: nop

.try

{

...

} // end .try

.finally

{

  IL_005d: ldloc.3

  IL_005e: call System.Threading.Monitor::Exit

  IL_0063: nop

  IL_0064: endfinally

} // end .finally

You see, it inserts an extra nop between Monitor.Enter and try/finally. Right at the nop instruction, a ThreadAbortException is thrown in this thread, leaving the lock to be orphaned. (The exact reason why the exception is thrown is unknown. It is definitely not thrown by our code.)

Joe Duffy from CLR team has discussed the exact symptom in his blog

http://www.bluebytesoftware.com/blog/PermaLink,guid,d9ff204a-a8a5-400e-bcbc-dedb90a7d11a.aspx

Writing managed code does give you more challenge in writing reliable product.