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