Share via


Lock(object) and ThreadAbortException

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

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

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

Comments

  • Anonymous
    July 30, 2007
    I wouldn't say managed code makes it more challenging to write a reliable product - it just gives you a different set of reliability problems to worry about. Reliability is always a challenge, no matter what language you work with.

  • Anonymous
    July 31, 2007
    Do you have a solution for that problem yet? It appears to me that it must be a common major slip in 'using' and 'lock' statement implementation. BTW, there is a way to amortise the trouble, by wrapping Monitor's functionality in CriticalFinalizer object. Even if async exception happens, the lock will be released sometimes latter. But it is not the true solution in general case. I think Microsoft should address async exception problem with something substantial.