Locks and exceptions do not mix

A couple years ago I wrote a bit about how our codegen for the lock statement could sometimes lead to situations in which an unoptimized build had different potential deadlocks than an optimized build of the same source code. This is unfortunate, so we've fixed that for C# 4.0. However, all is still not rainbows, unicorns and Obama, as we'll see.

Recall that lock(obj){body} was a syntactic sugar for

var temp = obj;
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. It's consistently bad now, which is better than being inconsistently bad. But there's an enormous problem with this approach. By choosing these semantics for "lock" we have made a potentially unwarranted and dangerous choice on your behalf; implicit in this codegen is the belief that a deadlocked program is the worst thing that can happen. That's not necessarily true! Sometimes deadlocking the program is the better thing to do -- the lesser of two evils. 

The purpose of the lock statement is to help you protect the integrity of a mutable resource that is shared by multiple threads. But suppose an exception is thrown halfway through a mutation of the locked resource. Our implementation of lock does not magically roll back the mutation to its pristine state, and it does not complete the mutation. Rather, control immediately branches to the finally, releasing the lock and allowing every other thread that is patiently waiting to immediately view the messed-up partially mutated state! If that state has privacy, security, or human life and safety implications, the result could be very bad indeed. In that case it is possibly better to deadlock the program and protect the messed-up resource by denying access to it entirely. But that's obviously not good either.

Basically, we all have a difficult choice to make whenever doing multi-threaded programming. We can (1) automatically release locks upon exceptions, exposing inconsistent state and living with the resulting bugs (bad) (2) maintain locks upon exceptions, deadlocking the program (arguably often worse) or (3) carefully implement the bodies of locks that do mutations so that in the event of an exception, the mutated resource is rolled back to a pristine state before the lock is released. (Good, but hard.)

This is yet another reason why the body of a lock should do as little as possible. Usually the rationale for having small lock bodies is to get in and get out quickly, so that anyone waiting on the lock does not have to wait long. But an even better reason is because small, simple lock bodies minimize the chance that the thing in there is going to throw an exception. It's also easier to rewrite mutating lock bodies to have rollback behaviour if they don't do very much to begin with.

And of course, this is yet another reason why aborting a thread is pure evil. Try to never do so!

Comments (39)
  1. Tom says:

    Great post, but a scary topic. I can’t help feel that the “take-away” from all this is to not use the C# lock keyword in production code. It seems like it is broken and isn’t getting fixed really.

    No, that’s not the takeaway. The takeaway is that locking is only a starting point in ensuring thread safety. Ensuring that the lock body is truly atomic is hard. Locks are not magic dust that you sprinkle on code and suddenly it gets safe. — Eric

  2. commongenius says:

    Since the only situation this change affects is when an exception is thrown immediately after Monitor.Enter and before the try is entered, which also means before the protected state has been mutated, I don’t see how this change implies any particular opinion about deadlocking versus state inconsistency.

    Perhaps I was unclear. This change does not imply any such opinion. The whole design of the lock statement implies that opinion. This change does not affect the more general problem, which was my point. — Eric

    More generally, isn’t the issue of an exception resulting in partially mutated state orthogonal to the issue of locking? The same situation would be true if there were not threading or locking involved, and an exception is thrown while mutating state. Anything which tries to read the partially mutated state after the exception is thrown could be in trouble. That’s why the general guidance on handling exceptions is, if the process might be executing in an unknown state, let it die.

    Yes, you have similar problems in single-threaded land, but it is harder to avoid the problem in mutli-threaded land. In a single-threaded situation, someone up the call stack can catch the exception and fix up the state if need be, or cleanly shut down the process before touching it again, or whatever. In a multi-threaded situation, the very moment the lock is unlocked, some thread could immediately be in there messing with the state. — Eric

  3. Pop Catalin says:

    I don’t think locks have anything to do with the fact that a unexpected exception leaves a resource in an inconsistent state.

    The worst thing is asynchronous exceptions from which there’s no true safeguard, unless you want to write some crazy almost impossible to test code with CERs, and which is not as easy to write as it might seem. And even if you do write it, I really don’t know how you could test it completely without trowing a an asynchronous exception at every instruction.

    On the other hand synchronous exceptions ideally should never affect the state of you application.

    But in order to achieve this you need a programming model, where you never commit state changes to shared resources until you finished all processing on them.


      lock (syncKey)


              tempResult1 = DoSomePotentiallyDangerousWork(sharedResource);

              tempResolt2 = DoSomeMoreDangerousWorkThatMightThrow(sharedResource, tempResul1);

              tempResult3 = DoMoreWork(sharedResource, tempResult2);

              * commit tempResult1, tempResoult2 , tempResoult3


    Ideally the commit is a simple assignment of a reference or value, that has very small changes of failure, or operations that follow the same principle, in case of exceptions the state is never mutated.

    I always think my code should behave as small units of work, or small transactions that should change state in the safest way possible, only committing state changes at the end of each unit.

  4. Claudio Friederich says:

    ihmo, the issue is not how the Lock statement is implemented, but rather is about why you should never use the ThreadAbortException.  Using the Abort method to stop a thread seems like a terrible thing to do.  Think about it – you stop a thread by arbitrarily triggering an exception in it, without underlying cause.  Therefore, the answer is, avoid using Thread.Abort like the plague.  If you need to be able to stop a thread, define a boolean flag, set it to abort the thread, and let the thread abort itself in a proper fashion, by checking the flag and shutting itself down cleanly, under its own control.  I have done multithreaded client and server code often, and never needed Thread.Abort.  Without Thread.Abort, the lock statement quirk described becomes a nonissue.  Ultimately, I think thread.Abort and the ThreadAbortException should just be eliminated from the framework to solve the problem.  But I agree with the design decision that a deadlock is the worst thing to happen.  I do not know of a case where it is not.  In server side apps, it means you have the whole IT department on your back, since they have nothing better to do than count server reboots, and for a client application, nothing is more exasperating for a user than an app that just freezes and sits there, needing to be end tasked.

    Indeed, thread abort exceptions are pure unmitigated evil and you should never use them. — Eric


  5. Andy Brummer says:

    I’ve got to agree with the other commenters.  The lock statement does one thing and one thing only; ensure that the monitor enter and monitor exit calls are matched properly.  That is getting fixed.  Making sure all the application code is exception neutral is a completely separate issue.

  6. susL says:

    I also agree with others. It’s the responsibility of the programmer to ensure appropriate  exception safety of the code. lock() must only ensure that resource is unlocked when some exception is thrown within its body

  7. Neil Whitaker says:

    I completely admire your writing and have great respect for your work. However in this case, as the other posters have said, exception safety is different from lock safety.

    We appear to be in violent agreement. πŸ™‚ The point of this article is that getting the locks right is only the first step; getting the program truly threadsafe in the face of all possible exceptions requires more thought. — Eric

    You write this:

    “Sometimes deadlocking the program is the better thing to do.”

    And yet the deadlock situation that has been fixed is one where the deadlock occurs before the try block begins executing, meaning we haven’t had a chance to mutate state yet.

    So, when this deadlock ever did occur in c# 3.0, it wasn’t preventing half-mutated state from occurring. It was just preventing my program from continuing to run.

    Life and safety critical code is definitely important. However, a deadlock can be deadly too. If my heart defibrillator or vehicle/aircraft/missile guidance system stops being able to respond to my commands, someone could be in big trouble.

    So let’s fix the problem we can right now, which is that deadlock (and especially the consistency problem).

    Meanwhile, let’s keep educating developers on how to write exception-tolerant code, and to avoid Thread.Abort whenever possible. Also, I look forward to framework and other enhancements that make it easier to write safe code. Transactional memory, for example, looks promising.

    Informing developers that there is a problem is the first step in education, which is what I’m attempting to do here. As for transactional memory, I think it is a great idea, but we have yet to see an implementation that does not entail an unacceptably high performance price for the common (transaction succeeds) scenario. Once we have that, I definitely want to look at language enhancements that take advantage of it. — Eric

  8. Jonathan Allen says:

    I think this whole thing is much ado about nothing. If you don’t use thread abort exceptions, this is a non-issue. If you do use them, you are screwed no matter what.

    So just don’t use thread abort exceptions and stop worrying about it.

  9. DRBlaise says:

    Will the C#4.0 fix also allow a TimeSpan or milliseconds to be passed in as a parameter to Enter so that an atomic setting of the lockWasTaken flag works when specifying a timeout?  It would be great to have a new version of the lock statement like below:

    lock (obj, timeout) { lockbody } else { timeoutbody }

    Sugar Coating for:

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

    Sadly, no. I agree that this would be nice, but the cost of the feature doesn’t pay for the benefit of the sugar. — Eric

  10. Pop Catalin says:

    @DRBlaise, t I don’t think "timed lock aqquires" is suck a frequent technique used in .Net that it requires a language construct to support it directly.

    Actually I’ve just ran an analyze of the Monitor.TryEnter(object, int) and Monitor.TryEnter(object, TimeSpan) using  Reflector and they aren’t used a single time throughout the standard .Net 3.5 assemblies (WPF + WCF included)

  11. DRBlaise says:

    I understand that the sugar coating was just pie in the sky, but will an Monitor.Enter or Monitor.TryEnter function be available to get an atomic setting of the lockWasTaken flag when passing in a TimeSpan or milliseconds?  I wouldn’t think that would take too much time to implement.

  12. Adam says:

    I don’t know how exception handling works in C#, but I’m guessing it’s not any more powerful than C++.

    Read Chris Brumme’s exegesis if you want the details of the relationship between C++ exception handling, win32 exception handling and managed exception handling. It is a fascinating read. — Eric 

      I don’t really know Lisp either, but I know that it has a fundamentally different and more powerful exception handling system.  For example, it’s possible to handle an exception, clean up, and go back to what you were doing.  You don’t need to unroll the stack and deal with things in some outer scope.  In a sense, you can cancel exceptions.  It’s sort of like how you can ignore exceptions in VB, except you can do real cleanup as well.  I think it’s actually more powerful than that, but the point is, you can do things with Lisp that are just flat impossible in C#.

    The price you pay is that it can be awfully brain-mangling to understand programs written using continuation passing style. See my blog archive for some articles on how to wrap your head around it. — Eric

    I haven’t thought it through, but I wouldn’t be surprised if this problem had a simple solution given a sufficiently powerful exception handling system.  A more appropriate subtitle might be “Locks and excessively simplistic exception handling systems do not mix”.

    Functional languages with CPS also emphasize programming without mutable state, eliminating the need for locks in the first place. — Eric

    But, assuming you’re stuck with C#, you still need to clean up, and you need to do it while the object is locked.  The syntactic sugar always needs to avoid the deadlock.  It’s job is not to clean up after execptions.  You still need to do that manually.  It’s easy:

    lock(foo) {
       try {
       finally {

    I think you got the code wrong. Surely that is meant to be

    lock(foo) {
       try {
       catch {

    You don’t want to clean up the mutation if no exception is thrown! — Eric

  13. configurator says:

    Since you mention the ThreadAbortException, what happens when:

    try {
    Monitor.Enter(temp, ref lockWasTaken);
    { body }
       if (lockWasTaken)
           // <—- The exception happens here

    Good question. In CLR v2 and higher the exception is delayed until the finally block is done. Which means that the thread might never end at all. Which is another reason why attempting to abort a thread is pure evil. No guarantee that it will actually work. — Eric

  14. Niels says:

    Just as an aside, javac does


    try { body }

    catch (Throwable t)



     throw t;



    which is the same as in a previous post, and seems a lot more sane to me.

  15. Dmitry Lomov says:

    Isn’t using also a problem? As in:

    using(var s = new StreamReader()) {…}

    which translates into

    var s = new StreamReader();
    try { … } finally { s.Dispose(); }

    and now you have the same issue.

    (I’ve seen people using IDisposable for locks also quite bit actually).

    Any plans to address this?

    Suppose an exception is thrown after the new but before the try. What’s the worst thing that can happen? The disposer does not run, and the garbage collector eventually cleans up the resource a while later. Remember, “using” was designed to allow you to more easily optimize the cleanup of scarce resources. If a thread abort happens to un-optimize that process, it’s probably not a big deal. (And if you are using “using” for something other than optimizing the cleanup of a scarce resource, then you’re using it off-label. I recommend that you do not use “using” to implement locking semantics.) — Eric

  16. configurator says:

    Using is even more problematic, since in the constructor anything can happen.

    Let’s suppose that using was translated to:

    StreamReader s;
    try {
       s = new StreamReader();
    } finally {
       if (s != null)

    What if there’s a ThreadAbortException after the resource is taken but before s is assigned? I see no way to fix that issue, actually.

    You don’t have to fix it. The GC will eventually release the resource. — Eric

    Eric: Does that delay happen for any finally block or only for a lock’s finally block?

    Any finally block. Locks do not generate special IL. — Eric 

    Also, of course there’s no guarantee! I had once a loop like this:

    while (!CalculationComplete()) {
       try {
       } catch (Exception e) {       
    ExceptionHandler.Handle(e); // ExceptionHandler logs the message and usually shows an error message but not in this specific case (client requirements)

    Note that any exception is caught and logged – including a ThreadAbortException. There was no way to actually abort that thread. only to abort a specific part of the calculation.

    Actually, I believe you cannot stop the thread abort exception. You can delay it indefinitely, but you cannot eat it and keep on trucking. If you try, you’ll find that the thread does in fact go down. In the next version of the CLR there will be even more “inedible” exceptions. — Eric

  17. Dmitry Lomov says:

    @configurator: yes, exactly, I do not see a good way to fix usings too.

  18. Pavel Minaev says:

    > Locks are not magic dust that you sprinkle on code and suddenly it gets safe.

    Yeah, STM is that magic dust πŸ™‚

  19. Jacco says:


    I am a bit disappointed. I actually thought the ThreadAbortException was a pretty genious solution to finish infinitely working threads (I actually am still using this :s). I assumed (wrongly I suppose) that the .NET Framework would take care of the tricky parts of doing something as dangerous as that.

    Sorry to disappoint, but this programming practice is dangerous and directly contrary to good programming practices. The only reason you should ever abort a thread is when you are doing an emergency shutdown and are trying to take down the entire appdomain. Design your multi-threaded applications so that threads can be taken down cleanly. — Eric

    A lot of threads I use look something like this:

    public void DoWork(object param) {
     WorkItem workItem;
     while (true) {
       try {
         lock(someQueue) {
           workItem = someQueue.Dequeue();
         if (workItem != null) {
           // repeated payload of this thread
         } else {
           Thread.Sleep(15 * 1000);
       } catch (Exception e) {
         // reraise any exxceptions I really not should try doing something about
         if (e is ThreadAbortException || e is OutOfMemoryException || e is StackOverflowException)
           throw e;
         // cleanup no reraiseunless decided fatal
         // …

    In future versions of the CLR, these exceptions will probably be “inedible” — you will not need to re-throw them. They’ll automatically be re-thrown if you attempt to handle them and continue. — Eric

    To stop these creatures I use the Thread.Abort abort (which throws the ThreadAbortException. Using Intellisense this seemed the right way to go.

    I know I should be using events in stead of an ever repeating while loop but somehow I find this set up easier to grasp.

    Wouldn’t it be nice if the would Framework not immediately stop but only in places where the TheadAbortException is actually caught (and maybe rethrown)?

    Regards, Jacco

  20. I don’t understand the dislike of ThreadAbortException.

    The way I see it, it’s an ideal way of stopping an ongoing bit of work.  Sure, it may cause an exception where it is not expected; but so long as you presume that the thread-relevant state is trash anyhow, it matters little what state (or, for that matter locks) it held; those should be released.  

    This is contrary to both fact and the intended design of the feature. You should never abort a thread unless you are attempting to do an emergency shutdown of an appdomain. — Eric

    Externally aborting a thread means it’s possible to have simpler processing code (no checking for stopping flags), means it’s possible to save execution resources if work-items are fairly granular (which they often are), and the drawbacks seem to apply when you cause such an exception and then actually expect the datastructures the thread was mutating to have a consistent state.

    I realize that ThreadAbort exceptions pose difficulty to the CLR designers, but there’s a real advantage to their usage that cannot be replicated by means of setting some abort flag (if that’s even possible – the code you want to abort may well be deep in external code – such as, for instance, other framework library code).

    Essentially, using “abort” flags represents fully executing the work item and then ignoring the result, whereas Thread.Abort represents trashing the current execution immediately.  The latter functionality isn’t useless, and I don’t see an alternative.

    If you need to take down a long-running unit of work that is full of code you do not control, a thread is the wrong way to structure that unit of work. We have work structures designed specifically for that scenario, namely processes and appdomains. If your application has the need to spawn off work in a way that the work can be cleanly killed halfway through regardless of what it is doing, you should be using the heavier-weight structures that were designed to facilitate that pattern. Using tools like threads for purposes that they were explicitly not designed for is a recipe for bugs. — Eric

  21. gOODiDEA.NET says:

    .NET ASP.NET Routing performance compare to HttpHandler LINQ on Objects Performance Why My ASP.NET Application

  22. gOODiDEA says:


  23. Dmitry Lomov says:

    Re using once again:

    There are a lot of people using disposable pattern (with usings) to implement “flag on/flag off” &c, so while it may not be the intended purpose, it is still quite conveninent and widespread.

    I am aware that this abuse is widespread. Being widespread does not make it a good idea. It is a bad idea to use our tools “off label” for purposes that they were never intended to be used for. And it should not be a surprise that when you do, you sometimes get unexpected bad behaviour. — Eric

    But here is the other question: how does Thread.Abort work with finalizable objects? As in:

    var s = new StreamReader();

    what if thread abort happen inside the call to constructor?

    Constructors are nothing special to the thread manager. They’re just methods that happen to be called right after an object is allocated. — Eric

    Will object get to finalazer queue in that case?

    Of course. It had better — the constructor might have already allocated objects that need finalization! — Eric

    If it does, will that mean that finilizer will see uninitialized object?

    Yes. So you had better make sure that you write your finalizable objects to be robust in the situation where constructors fail half way through. Since you already have to write your finalizers to be robust in the face of multi-threading race conditions, this shouldn’t be too much of an additional burden. (Finalizers run on a different thread than the main execution thread, so they have to be thread safe.) Remember, writing finalizable objects is an advanced topic for programmers who know exactly what the runtime finalization semantics are. If you do not know how it works, do what I do. I do not attempt to write a finalizer without help from someone who does understand it. — Eric

  24. Dmitry Lomov says:

    @eric: yep, finalizers are difficult to get right πŸ™‚

    I still do not feel that using the "using" in the way I desribed is a bad idea (well, as long as you do not abort your threads). Here is a nice article by Hans Boehm on a difference between destructors and finalizers (http://www.hpl.hp.com/techreports/2002/HPL-2002-335.html)

    Now, IDisposable.Dispose is a (sort of a) destructor (invoked synchronously when "static" lifetime of an object ends), and finalizer is, well, a finalizer.

    [Hans’s C++ example for usability of destructors involves locks, but one can also imagine completely managed and harmless examples, e.g.: using(new EventListener(o)) { … }, where EventListener subscribes to certain o’s event in constructor and unsubscribes from the event in Dispose]

    I feel that C# does a very good job here in separating destructors and finalizers and giving the programmer a nice syntax for both – so I do not quite see why you consider it an abuse of the feature. I feel you are trying to take away a very nice and proper element of the language πŸ™‚  – which not many other languages have btw!

    Of course, Thread.Abort kills all the nice properties of all that – and writing cleanly-abortable threads is difficult, and 99% of the code written is not cleanly abortable anyway.

    So I would say it is quite ok just to say that "using" is not cleanly abortable, while the "lock" with the new semantics is (with the caveats you have so clearly exposed in your post)

  25. gcie says:

    [Hans’s C + +-Beispiel für die Nutzbarkeit von Destruktoren die Schlösser, aber man kann sich auch völlig harmlos und verwaltet Beispiele, zB: mit (neuen EventListener (o)) (… ), Wenn sich an bestimmten EventListener o Veranstaltung in Konstruktor und unsubscribes von der Veranstaltung in Entsorgen]

  26. yy165 says:

    [Hans du C + + par exemple pour la facilité d’utilisation des destructeurs des écluses, mais on peut aussi imaginer complètement inoffensifs géré et exemples, par exemple: en utilisant (nouveau EventListener (o)) (… ), Où EventListener souscrit à certaines o dans le constructeur de l’événement et se désabonne de la manifestation en Eliminer]

  27. jianfeiff says:

    Annuler un thread extérieur signifie qu’il est possible de faire plus simple de transformation de code (pas de contrôle pour l’arrêt des drapeaux), signifie qu’il est possible d’économiser des ressources si l’exécution du travail sont assez granuleux (qui sont souvent), et les inconvénients semblent s’appliquer lorsque vous cause une telle exception, et puis en fait attendre le datastructures le fil est en mutation à un état cohérent.

  28. gamedeath says:

    μ™ΈλΆ€μ—μ„œ μŠ€λ ˆλ“œλ₯Ό 쀑지 κ·Έκ±Έ 막을 ν”Œλž˜κ·Έ (더 κ°„λ‹¨ν•˜κ²Œ μ²˜λ¦¬ν•˜λŠ” μ½”λ“œκ°€ 확인 κ°€λŠ₯), μˆ˜λ‹¨ μ‹€ν–‰ μžμ› – μƒν’ˆ 경우 μƒλ‹Ήνžˆ μ„ΈλΆ„ν™”ν•˜λŠ” μž‘μ—…μ„ μ €μž₯ν•  μˆ˜μžˆμ–΄ (자주)κ°€ 있고, 뜻 단점을 μ μš©ν•  λ•Œ λ°œμƒν•  것 이런 μ˜ˆμ™Έλ₯Ό μ‹€μ œλ‘œ μŠ€λ ˆλ“œ datastructures κΈ°λŒ€κ°€ μΌκ΄€μ„±μžˆλŠ” μƒνƒœκ°€ λŒμ—°λ³€ν–ˆλ‹€.

  29. configurator says:

    We have, in our program, a window that shows an insurance policy. The calculations needed to get its values are *extremely* complicated and take 2 or 3 minutes – but that didn’t matter really. Until there was a window required that showed the results “online”. This means that whenever the user changes a field, the results have to be recalculated (never mind that they take time to show, we use a progress bar and all).

    So what happens now is:

    The user changes a field. A thread is created for the calculation. Then the user changes another field. That thread is aborted, everything it did is completely irrelevant and is scrapped, and a new thread is created. If the user waits a while, the results are shown.

    This works perfectly at the moment, I might add.

    Since you’re saying Thread.Abort is the wrong thing to do here, how would you do this? We are extremely reluctant to change the calculation method, since it involves a lot of Code Voodoo (really *really* bad code).

    Deciding what to do about that situation depends on the immediate and long-term business goals of your organization. I am reluctant to touch working, debugged code even if it is in many ways horrid unless doing so meets a long-term business goal.

    For example, if this code is likely to be modified a lot in the future, either because it is at present a bug farm, or because the policies which it implements are likely to change, then I’d consider carefully re-engineering the code so that it is (1) easier to understand and modify in the future and (2) actually engineered to fulfill the needs of the usage case. If the calculation code needs to be interruptable then design it to be interruptable and engineer interrupt points into it. Then you won’t need to abort the thread; you’ll have a mechanism that lets you shut it down cleanly.

    If, on the other hand, the code is fine as it is and there’s no need to change it, then don’t spend thousands of dollars of company money for no gain. Just add a comment saying that this has been identified as a bad programming practice, and consider fixing it in the future if things change. — Eric

  30. configurator says:

    "Actually, I believe you cannot stop the thread abort exception." I’m sure I did it somehow, without expecting it. I’m not sure how, though – this was years ago.

  31. Pavel Minaev says:

    > I am aware that this abuse is widespread. Being widespread does not make it a good idea. It is a bad idea to use our tools "off label" for purposes that they were never intended to be used for. And it should not be a surprise that when you do, you sometimes get unexpected bad behaviour.

    Eric, but isn’t using+IDispose just the C# implementation of RAII; and if so, why not use it as such?

    As you yourself said already, Thread.Abort breaks so many other things that it is no surprise it breaks RAII too. But in its absence, what’s wrong with using?

  32. Joe Albahari says:

    Aborting a thread is quite safe if you run the thread in its own AppDomain and recreate its domain after aborting the thread. This is not as difficult or inefficient as it sounds and is often a very practical approach.

    Correct. You don’t want to take a thread down unless you are doing so in the process of taking down its appdomain. If you cannot write a thread that can shut itself down cleanly, then the appdomain is the sensible structure to use for work that may be arbitrarily cancelled. — Eric

    Please don’t deprecate or in any way cripple Thread.Abort – it is a powerful and essential feature if used properly. Without it, you wouldn’t be able to cancel a runaway query in LINQPad!


  33. Judah says:

    "…but it’s not all rainbows, unicorns, and Obama…"

    Haha! Thanks for that.

  34. Ramblings says:

    I am probably going to receive some serious hate mail for this blog posting. As the years have gone by, I’ve grown to believe that exceptions were a laudable idea gone almost entirely awry. Perhaps there is some esoteric programming…

  35. Mike says:

    By "rainbows, unicorns and Obama" are you perhaps referring to this?


  36. Greg says:

    – Do not do things that can throw exceptions in a critical section

    – Always have an explicit cleanup after the criticial seciotn is exited to handle obscure errors

       bool lock_obtained = false

       lock (abc)


           lock_obtained = true

           do work

           unlock (abc)


      if (lock_obtained == TRUE OR abc.is_locked()) then unlock(abc)

    – Important for code quality/readability – Put as little code as possible inside of the lock/unlock body by making the guts of a locked section a function call.  This makes it much easier to visually see that the lock obtain and lock cleanup code exists around the critical section.

    – Important for correctness – Make functions that are used inside of a critical section STATIC so that they do not rely on an instantiated object and pass in all data used by the critical section (i.e., no global variables) if possible.  This avoids the common problem of shared access to data in multithreded systems.  The critical section should not refer to any resource that it is not passed and if possible not rely on allocated objects (open file handles).

    – A safer alternative is to queue work done by critical sections if possible.  Winforms and win32 gui applications would routinely receive an interrupt message and call postmessage to queue it back to the main GUI’s thread without doing any real work so that the main GUI thread could process the message/event normally without concurrency penalty or critical sections.  This is commonly done in old school C applications with the interrupt handlers since many older operating systems could not handle reentrant executables witout great programming pain (dos, unix system V, etc)

  37. Steve says:

    Eric, I must respectfully disagree with the statement that the change makes things consistently bad.  The implicit contract here that once you exit the braces the lock will always be released.  My opinion is  having syntactic sugar that does not perform as expected is very nasty.

    "The takeaway is that locking is only a starting point in ensuring thread safety. Ensuring that the lock body is truly atomic is hard. Locks are not magic dust that you sprinkle on code and suddenly it gets safe."

    I completely agree.  The truth is that writing good multithreaded code is very hard; and its not any easier when things do not work as expected

  38. TheCPUWizard says:

    Regarding the comment earlier on this thread regarding transactional memory…..

    I was involved in a project that achieved this nearly 20 years ago, with acceptable performance (ie you could not statistically measure any performance difference using the transactional memory and normal memory)

    Of course I had one BIG advantage….it was custom HARDWARE that implemented the transactional memory.

    Great post on while lock(…) did not and does not, and probably never will magically make a system "safe"..on conventional hardware..

  39. SB says:

    If I'm understanding you correctly you are saying attempt the lock but return it to its previous state as a sort of roll back mechanism?

    public void Process(Car car, string make, string model)


               var originalCar = car;

               var lockObj = new object();



                   lock (lockObj)


                       car.Make = make;

                       car.Model = model;





                   //an error occured

                   //return car to previous state

                   car = originalCar;






Comments are closed.

Skip to main content