看看C#中用lock关键实现同步的原理 [转]
我们知道C#的关键字都对应着.net Framework的类型,对象,比如string 对应String。那么“Lock”是如何对应的呢,似乎不能像string一样那么明显地找一个对应的东西。但是通过使用“ildasm”工具,察看.net生成的中间代码,很容易能发现lock的工作机制:调用了System.Threading.Monitor.Enter/Exit来实现同步互斥。看下面一段代码:
我们知道C#的关键字都对应着.net Framework的类型,对象,比如string 对应String。那么“Lock”是如何对应的呢,似乎不能像string一样那么明显地找一个对应的东西。但是通过使用“ildasm”工具,察看.net生成的中间代码,很容易能发现lock的工作机制:调用了System.Threading.Monitor.Enter/Exit来实现同步互斥。看下面一段代码:
object someObject = new object();
. . .
private void button1_Click(object sender, EventArgs e)
{
lock(someObject)
{
// Your code here
} }
利用ildasm打开编译过的代码,下面是生成的IL(中间语言)的代码:
.method private hidebysig instance void button1_Click(object sender, class [mscorlib]System.EventArgs e) cil managed
{
// Code size 29 (0x1d)
.maxstack 2
.locals init ([0] object CS$2$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld object WindowsApplication1.Form1::someObject
IL_0007: dup
IL_0008: stloc.0
IL_0009: call void [mscorlib]System.Threading.Monitor::Enter(object)
IL_000e: nop
.try
{
IL_000f: nop
IL_0010: nop
IL_0011: leave.s IL_001b
} // end .try
finally
{
IL_0013: ldloc.0
IL_0014: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_0019: nop
IL_001a: endfinally
} // end handler
IL_001b: nop
IL_001c: ret
} // end of method Form1::button1_Click
然后再看看显示调用System.Threading.Monitor.Enter/Exit进行同步的代码:(.NET4以前)
private void button1_Click(object sender, EventArgs e)
{
System.Threading.Monitor.Enter(someObject);
try
{
// Your code here
}
finally
{
System.Threading.Monitor.Exit(someObject);
} }
察看它的IL:
.method private hidebysig instance void button1_Click(object sender, class [mscorlib]System.EventArgs e) cil managed
{
// Code size 34 (0x22)
.maxstack 1
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld object WindowsApplication1.Form1::someObject
IL_0007: call void [mscorlib]System.Threading.Monitor::Enter(object)
IL_000c: nop
.try
{
IL_000d: nop
IL_000e: nop
IL_000f: leave.s IL_0020
} // end .try
finally
{
IL_0011: nop
IL_0012: ldarg.0
IL_0013: ldfld object WindowsApplication1.Form1::someObject
IL_0018: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_001d: nop
IL_001e: nop
IL_001f: endfinally
} // end handler
IL_0020: nop
IL_0021: ret } // end of method Form1::button1_Click
通过比较很容易发现这两段代码生成的中间语言代码几乎是一样的,至此我们应该能够很明白lcok的工作原理了。
转自:http://space.itpub.net/22425738/viewspace-616320
但是,这种实现逻辑至少理论上有一个错误:当Monitor.Enter(lockObj);刚刚完成,还没有进入try区的时候,有可能从其他线程发出了Thread.Abort等命令,使得该线程没有机会进入try...finally。也就是说lockObj没有办法得到释放,有可能造成程序死锁。这也是Thread.Abort一般被认为是邪恶的原因之一。
DotNet4开始,增加了Monitor.Enter(object,ref bool)重载。而C#编译器会把lock展开为更安全的Monitor.Enter(object,ref bool)和Monitor.Exit:
- C# code
-
lock(lockObj) { //...}
-
////相当于(DotNet 4):
-
bool lockTaken =false;
-
try
-
{
-
Monitor.Enter(lockObj,ref lockTaken);
-
//
-
}
-
finally
-
{
-
if (lockTaken) Monitor.Exit(lockObj);
-
}
现在Monitor.TryEnter在try的保护下,“加锁”成功意味着“放锁”将得到finally的保护。

浙公网安备 33010602011771号