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_003a: ldfld stateLock
IL_0041: call System.Threading.Monitor::Enter
} // end .try
IL_005e: call System.Threading.Monitor::Exit
} // 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
Writing managed code does give you more challenge in writing reliable product.