閱讀763 返回首頁    go 阿裏雲 go 技術社區[雲棲]


並發中的同步--WCF並發體係的同步機製實現

在《WCF 並發的本質》中,我們談到了WCF提供的三種不同的並發模式,使開發者可以根據具體的情況選擇不同的並發處理的策略。對於這三種並發模式,Multiple采用的並行的執行方式,而Single和Reentrant則是采用串行的執行方式。串行執行即同步執行,在WCF並發框架體係中,這樣的同步機製是如何實現的呢?

一、Concurrency.Single模式下的同步實現

實際上,WCF並發框架體係下針對Concurrency.Single模式的實現非常簡單,其本質就是對InstanceContext進行加鎖。如果采用反編譯工具查看InstanceContext的定義,你會發現InstanceContext類中定義了一個類型為System.Object名為ThisLock的內部屬性,而該屬性實際上就是對基類CommunicationObject同名屬性的引用,相關代碼入下所示。WCF就是通過對InstanceContext的ThisLock進行加鎖,確保了對InstanceContext的同步訪問。

   1: public sealed class InstanceContext : CommunicationObject, IExtensibleObject<InstanceContext>
   2: {
   3:     //其它成員
   4:     internal object ThisLock
   5:     {
   6:         get
   7:         {
   8:             return base.ThisLock;
   9:         }
  10:     }
  11: }
  12: public abstract class CommunicationObject : ICommunicationObject
  13: {
  14:     //其它成員
  15:     protected object ThisLock { get; }
  16: }

具體來講,WCF服務端運行時在處理服務調用消息請求之後,利用實例上下文提供者(InstanceContextProvider)創建新的或者獲取現有的InstanceContext。然後,WCF會將請求消息分發給該InstanceContext對消息進行進一步處理。在處理操作執行之前,如果發現相應的服務采用的並發模式是ConcurrencyMode.Single,WCF運行時會試圖獲取InstanceContext的ThisLock上的鎖,或者說後續的操作進行再對InstanceContext的ThisLock鎖定的情況下執行的。這樣就保證了單一的InstanceContext對象在ConcurrencyMode.Single並發模式下永遠是以同步的方式被調用的。

二、Concurrency.Reentrant模式下的同步實現

在ConcurrencyMode.Single並發模式下,從請求被WCF服務端運行時分發給相應的InstanceContext到請求處理完成的整個過程中,InstanceContext被鎖定。如果在服務操作執行過程中涉及到對客戶端的回調,並且回調操作采用請求/回複消息交換模式,當被WCF服務端運行時接收到從客戶端返回的回複消息後,會將請求消息再次分發給相同的InstanceContext。運行時分發回調回複消息與普通服務調用請求消息采用相同的機製,同樣需要在對InstanceContext成功鎖定的情況下進行。很明顯,這樣產生了死鎖(Deadlock)。

所以,如果在服務操作執行過程中需要對客戶端實施回調,要麼將采用單向(One-way)的方式進行回調,要麼將服務的並發模式設置成ConcurrencyMode.Reentrant或者ConcurrencyMode.Multiple。否則,如圖1所示的InvalidOperationException異常會在進行回調操作的時候拋出。從異常消息我們可以看出,VS的漢化真的不敢恭維,如果要正常理解異常消息的含義,你需要知道這裏的“郵件”、“可重輸入”和“多個”是依次對“Message”、“Reentrant”和“Multiple”的翻譯。

image

圖1 在Single模式執行回調導致的異常

如果我們真的需要在服務操作過程中實施基於請求/回複模式的回調,毫無疑問采用Concurrency.Multiple並發模式可以解決死鎖的問題,因為Concurrency.Multiple模式根本就是存在對InstanceContext加鎖的問題。那麼,在Concurrency.Reentrant模式下,WCF並發框架體係又是如何解決這個問題的呢?

Reentrant,翻譯成漢語就是“重入”(VS將其翻譯成“重輸入”簡直莫名其妙),意思是服務操作過程中完成了對外調用(Call Out)還能重新回到相應的位置繼續執行。同Concurrency.Single模式一樣,WCF運行時將調用請求消息分發給相應的InstanceContext之前,會先對其加鎖。但是,在開始實施回調的之前,對InstanceContext的鎖定會被解除,當回調返回後再對其加鎖。

對於Concurrency.Reentrant有一點需要特別說明,當服務端進行回調時,由於加載InstanceContext上的鎖會被釋放,意味著其它服務請求會被分發給該InstanceContext。當回調返回的時候,如果InstanceContext正被用於才處理在進行回調過程抵達的請求,雖然自己是先來者,依然會等待,因為重入後的InstanceContext被鎖定。如果等待的時間超過設定的超時時限,客戶端會拋出TimeoutException異常。

由於WCF的並發是針對某個封裝了服務實例的InstanceContext而言的,所以在不同的實例上下文模式下,會表現出不同的並發行為。在下一篇文章中,我將從具體的實例上下文模式的角度來剖析WCF的並發,敬請期待。


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-27 15:05:10

  上一篇:go  WCF並發(Concurrency)的本質:同一個服務實例上下文(InstanceContext)同時處理多個服務調用請求
  下一篇:go  實踐重於理論——創建一個監控程序探測WCF的並發處理機製