WCF死鎖三種不同方式介紹
用過WCF的朋友們應該會清楚的認識到,當我們在使用回調(diào)契約時,通常會出現(xiàn)死鎖的情況出現(xiàn)。那么如何才能正確的解決WCF死鎖問題呢?我們今天就為大家詳細介紹了幾種解決方案,供大家參考學習。#t#
例如,當客戶端執(zhí)行服務操作時,向客戶端發(fā)出的調(diào)用會阻塞服務端進程,以等待服務操作執(zhí)行完畢。而在該服務操作中,又獲得了回調(diào)契約對象的引用(或者獲得保存的回調(diào)契約副本),并執(zhí)行回調(diào)操作。由于服務類被配置為單線程訪問,則服務實例是與鎖相關聯(lián)的。如果回調(diào)對象也需要返回同一個鎖的所有權,簡單的說,就是指當回調(diào)的應答消息也需要獲得與服務實例關聯(lián)的相同的鎖時,就會導致死鎖。因為此時服務線程已經(jīng)被阻塞,服務操作正在等待回調(diào)操作執(zhí)行完畢,而回調(diào)操作卻又在等待服務釋放鎖,自然會產(chǎn)生鎖的爭用。
解決WCF死鎖的辦法有三個,一個是將服務配置為允許多線程訪問,但這會增加服務開發(fā)者管理多線程的負擔。第二個方案是將回調(diào)設置為重入(Reentrancy),如下所示:
- [ServiceBehavior(ConcurrencyModeConcurrencyMode =
ConcurrencyMode.Reentrant)]- class MyService : IMyContract
- {
- public void DoSomething( )
- {
- IMyContractCallback callback = OperationContext.Current.
GetCallbackChannel<IMyContractCallback>( );- callback.OnCallback( );
- }
- }
所謂“重入”,是指對同步域擁有獨占訪問權的線程A調(diào)用了同步域之外對象的方法,此時,另外的線程B若要訪問該同步域,則線程A將釋放對同步域的鎖,允許線程B進入。直到線程B執(zhí)行完畢并釋放對同步域的鎖后,線程A將重新進入該同步域。配置回調(diào)為重入時,因為服務對象是與線程關聯(lián)的,屬于同步域的對象,而回調(diào)對象則屬于同步域之外的對象。由于服務被配置為重入,則服務調(diào)用回調(diào)引用時會釋放鎖。然后將回調(diào)返回給客戶端,控制權則返回給服務,服務會重入并重新獲取鎖。這樣就解決了死鎖的問題。
第三種方案則是將回調(diào)操作設置為單向操作。此時,回調(diào)調(diào)用不會產(chǎn)生應答消息,服務操作一旦執(zhí)行了回調(diào)操作,就會繼續(xù)執(zhí)行,回調(diào)對象不會爭用與服務實例關聯(lián)的鎖,從而解決了WCF死鎖問題。
- interface IMyContractCallback
- {
- [OperationContract(IsOneWay = true)] void OnCallback( );
- }
在使用回調(diào)對象時,需要考慮到客戶端代理可能會被關閉,如果此時調(diào)用回調(diào),就會引發(fā)一個ObjectDisposedException異常。“因此,對于客戶端而言,當它不再需要接收回調(diào)或者客戶端應用程序已經(jīng)關閉時,***能夠通知服務。”本書給出了解決這一問題的方法,就是為服務契約增加兩個操作Connect()與Disconnect()。其中,Disconnect()正是起到了通知服務的作用,它在客戶端代理關閉的情況下,可以將當前的回調(diào)對象引用從列表中移除。至于Connect()方法則是出于對稱的目的而引入,但引入它還有一個好處是,它可以使得客戶端能夠多次地連接或斷開。實現(xiàn)Connect()與Disconnect()方法的代碼如下:
- static List<IMyContractCallback> m_Callbacks =
new List<IMyContractCallback>( );- public void Connect( ) {
- IMyContractCallback callback = OperationContext.Current.
GetCallbackChannel<IMyContractCallback>( );- if(m_Callbacks.Contains(callback) == false)
- {
- m_Callbacks.Add(callback);
- }
- }
- public void Disconnect( )
- {
- IMyContractCallback callback = OperationContext.Current.
GetCallbackChannel<IMyContractCallback>( );- if(m_Callbacks.Contains(callback) == true)
- {
- m_Callbacks.Remove(callback);
- }
- else
- {
- throw new InvalidOperationException("Cannot find callback");
- }
- }
以上就是我們?yōu)榇蠹医榻B的幾種不同的WCF死鎖解決方法。


















