Should a return statement be inside or outside a lock?

后端 未结 9 2117
别那么骄傲
别那么骄傲 2020-12-12 18:32

I just realized that in some place in my code I have the return statement inside the lock and sometime outside. Which one is the best?

1)

void exampl         


        
相关标签:
9条回答
  • 2020-12-12 19:20

    It doesn't make any difference; they're both translated to the same thing by the compiler.

    To clarify, either is effectively translated to something with the following semantics:

    T myData;
    Monitor.Enter(mutex)
    try
    {
        myData= // something
    }
    finally
    {
        Monitor.Exit(mutex);
    }
    
    return myData;
    
    0 讨论(0)
  • 2020-12-12 19:20

    For what it's worth, the documentation on MSDN has an example of returning from inside of the lock. From the other answers on here, it does appear to be pretty similar IL but, to me, it does seem safer to return from inside the lock because then you don't run the risk of a return variable being overwritten by another thread.

    0 讨论(0)
  • 2020-12-12 19:20

    Note: I believe this answer to be factually correct and I hope that it is helpful too, but I'm always happy to improve it based on concrete feedback.

    To summarize and complement the existing answers:

    • The accepted answer shows that, irrespective of which syntax form you choose in your C# code, in the IL code - and therefore at runtime - the return doesn't happen until after the lock is released.

      • Even though placing the return inside the lock block therefore, strictly speaking, misrepresents the flow of control[1], it is syntactically convenient in that it obviates the need for storing the return value in an aux. local variable (declared outside the block, so that it can be used with a return outside the block) - see Edward KMETT's answer.
    • Separately - and this aspect is incidental to the question, but may still be of interest (Ricardo Villamil's answer tries to address it, but incorrectly, I think) - combining a lock statement with a return statement - i.e., obtaining value to return in a block protected from concurrent access - only meaningfully "protects" the returned value in the caller's scope if it doesn't actually need protecting once obtained, which applies in the following scenarios:

      • If the returned value is an element from a collection that only needs protection in terms of adding and removing elements, not in terms of modifications of the elements themselves and/or ...

      • ... if the value being returned is an instance of a value type or a string.

        • Note that in this case the caller receives a snapshot (copy)[2] of the value - which by the time the caller inspects it may no longer be the current value in the data structure of origin.
      • In any other case, the locking must be performed by the caller, not (just) inside the method.


    [1] Theodor Zoulias points out that that is technically also true for placing return inside try, catch, using, if, while, for, ... statements; however, it is the specific purpose of the lock statement that is likely to invite scrutiny of the true control flow, as evidenced by this question having been asked and having received much attention.

    [2] Accessing a value-type instance invariably creates a thread-local, on-the-stack copy of it; even though strings are technically reference-type instances, they effectively behave like-value type instances.

    0 讨论(0)
提交回复
热议问题