locking a resource via lock within try. Is it wrong?

前端 未结 3 981
走了就别回头了
走了就别回头了 2021-02-05 05:00

Is there anything wrong with using lock with a try block? I remember reading somewhere that we should always try to put minimum amount of code within try block and lock itself i

3条回答
  •  滥情空心
    2021-02-05 05:31

    I need to deal with the fact that the code within that lock block can throw exception

    And there's your problem. That's a terrible situation to be in.

    Why are you locking in the first place? Usually the reason why you lock something is because you want to implement the following logic:

    • lock the door
    • make a mess
    • clean it up
    • unlock the door

    If you do that, then no one who honours the locked door ever sees the mess.

    For example, you might want to swap values of variables "left" and "right" in a threadsafe manner, so you:

    • take the lock
    • read the left variable into tempLeft
    • read the right variable into tempRight
    • write tempLeft into right
    • we just made a mess; the original value of 'right' has gone missing
    • write tempRight into left
    • we've cleaned up the mess, all is well with the world again
    • release the lock

    Now suppose an exception is thrown after the mess is made. What happens? We jump straight to the unlock, leaving the mess for another thread to see.

    That's why you should never throw an exception inside a lock; it completely defeats the purpose of the lock! The whole point of a lock is to ensure that state is always observed to be consistent by all threads except the one responsible for cleaning up the mess.

    If you have an exception that can be thrown from inside a lock, the best thing to do is to get out of that horrible situation. If you can't do that, then make sure that you can either (1) destroy the process utterly as soon as the exception escapes the lock, so that the mess you made cannot cause data loss or other harm -- do a FailFast and nuke the process from orbit, it's the only way to be sure -- or (2) write rollback code that undoes whatever operation you were attempting before the lock is exited; that is, clean up the mess back to the original state.

    If the latter is your strategy then don't put the try block outside the lock; it's useless there because the instant control leaves the lock via the exception another thread can be crashing and dying because of the mess you left exposed to it. Put the try that deals with the exception inside the lock:

    lock(whatever)
    {
        try
        {
            MakeAMess();
        }
        finally
        {
            CleanItUp();
            // Either by completing the operation or rolling it back 
            // to the pre-mess state
        }
    }
    

    If you have strong reliability requirements then dealing with locked critical sections which can throw exceptions is an extremely difficult programming task best left to experts; you might consider using a constrained execution region if you find yourself in this situation a lot.

提交回复
热议问题