13.4 对锁和字段风格的事件的微小改变
13.4.1 健壯的鎖
1 class Program 2 { 3 static object locker = new object(); 4 static void Main(string[] args) 5 { 6 List<string> list = new List<string>(); 7 lock (locker) 8 { 9 list.Add("item"); 10 } 11 12 //在C# 4之前——包括使用C# 4處理.NET 4之前的東西時(shí)——以上語(yǔ)句將被有效地編譯為下面 的代碼: 13 14 object tmp = locker; 15 Monitor.Enter(tmp); 16 try 17 { 18 list.Add("item"); 19 } 20 finally 21 { 22 Monitor.Exit(tmp); 23 } 24 } 25 }這沒(méi)有問(wèn)題,并且它還避免了一些問(wèn)題。我們要確保釋放的監(jiān)視器與獲取的是同一個(gè),因此
首先將被鎖定內(nèi)容的引用復(fù)制到一個(gè)臨時(shí)局部變量?jī)?nèi) 。這同時(shí)意味著鎖的表達(dá)式只會(huì)進(jìn)行一
次求值。然后我們?cè)?try 語(yǔ)句塊之前獲取鎖。因此如果獲取鎖的線程異常終止,則不會(huì)執(zhí)行
finally 塊中釋放鎖的語(yǔ)句。這還將導(dǎo)致另一個(gè)問(wèn)題:如果線程在獲取鎖之后和進(jìn)入 try 塊之前
異常終止,我們也無(wú)法釋放鎖。這可能會(huì)導(dǎo)致死鎖——其他線程將一直等待該線程釋放鎖。盡管
CLR一直以來(lái)都在努力阻止類(lèi)似事情發(fā)生,但也不是完全沒(méi)有可能發(fā)生。
我們所需要的,是一種原子地獲取鎖并知道它已經(jīng)被獲取的方式。幸運(yùn)的是,.NET 4新增加
了 Monitor.Enter 的重載,C# 4的編譯器將使用這種方式:
13.4.2 字段風(fēng)格的事件
值得簡(jiǎn)單一提的是,C# 4對(duì)字段風(fēng)格事件的實(shí)現(xiàn)方式作了兩處修改。盡管它們是潛在的破壞性更改,但似乎不會(huì)對(duì)你產(chǎn)生什么影響。
總之,字段風(fēng)格的事件像字段一樣進(jìn)行聲明,不再包含顯式的 add/remove 語(yǔ)句塊,如下:
首先,線程安全的實(shí)現(xiàn)方式發(fā)生了改變。在C# 4之前,字段風(fēng)格的事件生成的代碼鎖定的是
this (實(shí)例事件)或聲明事件的類(lèi)型(靜態(tài)事件)。而C# 4中,編譯器實(shí)現(xiàn)了線程安全,對(duì)原子
的訂閱和退訂使用了 Interlocked.CompareExchange<T> 。與之前對(duì) lock 語(yǔ)句的修改不同,
面對(duì)舊版本的.NET Framework時(shí),這項(xiàng)更改同樣適用。
其次,在聲明事件的類(lèi)中,事件名稱(chēng)的含義改變了。以前,在聲明事件的類(lèi)中訂閱(或退訂)
事件——如 Click += DefaultClickHandler; ——將直接使用后臺(tái)字段,完全跳過(guò) add/remove
實(shí)現(xiàn)。現(xiàn)在情況變了,使用 += 或 -= 時(shí),事件的名稱(chēng)就指向事件本身,而不再是后臺(tái)字段。當(dāng)名
稱(chēng)用于其他意圖時(shí)(通常為分配或調(diào)用),則仍然指向后臺(tái)字段。
盡管在平時(shí)使用時(shí)你可能不會(huì)注意這兩處改變,不過(guò)它們是合理的,可以使一切變得整潔。
Chris Burrows在他的博客中深入研究了這個(gè)話題,想了解更多內(nèi)容可以參考http://mng.bz/Kyr4。
?
轉(zhuǎn)載于:https://www.cnblogs.com/kikyoqiang/p/10116459.html
總結(jié)
以上是生活随笔為你收集整理的13.4 对锁和字段风格的事件的微小改变的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java 并发
- 下一篇: 化验室的废液处理装置怎么安装?