Lock statement vs Monitor.Enter method

寵の児 提交于 2019-11-27 12:02:05
Brian Gideon

It is because the reference pointed to by test1 is assigned to the local variable CS$2$0000 in the IL code. You null out the test1 variable in C#, but the lock construct gets compiled in such a manner that a separate reference is maintained.

It is actually quite clever that the C# compiler does this. Otherwise it would be possible to circumvent the guarentee the lock statement is supposed to enforce of releasing the lock upon exiting the critical section.

I do not see any difference between lock statement and Monitor.Enter call.

Look more carefully. The first case copies the reference to a second local variable to ensure that it stays alive.

Notice what the C# 3.0 spec says on the subject:

A lock statement of the form "lock (x) ..." where x is an expression of a reference-type, is precisely equivalent to

System.Threading.Monitor.Enter(x);
try { ... }
finally { System.Threading.Monitor.Exit(x); }

except that x is only evaluated once.

It's that last bit -- except that x is only evaluated once -- that is the key to the behaviour. In order to ensure that x is evaluated only once we evaluate it once, store the result in a local variable, and re-use that local variable later.

In C# 4 we've changed the codegen so that it is now

bool entered = false;
try { 
  System.Threading.Monitor.Enter(x, ref entered);
  ... 
}
finally { if (entered) System.Threading.Monitor.Exit(x); }

but again, x is only evaluated once. In your program you are evaluating the lock expression twice. Your code really should be

    bool lockTaken = false;   
    var temp = test2;
    try {   
        System.Threading.Monitor.Enter(temp, ref lockTaken);   
        test2 = null;   
        Console.WriteLine("Manual collect 3.");   
        GC.Collect();   
        GC.WaitForPendingFinalizers();   
        Console.WriteLine("Manual collect 4.");   
        GC.Collect();   
    }   
    finally {   
       System.Threading.Monitor.Exit(temp);   
    }  

Now is it clear why this works the way it does?

(Also note that in C# 4 the Enter is inside the try, not outside as it was in C# 3.)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!