日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CallContext和多线程

發(fā)布時間:2025/6/17 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CallContext和多线程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  前一段時間正好要在某個網(wǎng)頁程序上開一個多線程調(diào)用多個組件的嘗試,這些組件是有其他團(tuán)隊開發(fā)的(如:印度/俄羅斯),所以修改它們的代碼看起來是不太現(xiàn)實的,但是,令人惱火的是他們的代碼中大量的用到了AppContext.Current這個對象(實際上是用了HttpContext.Current.Item來存儲的),而一旦異步,HttpContext.Current就不復(fù)存在,自然就會不停的報出空引用異常,看起來異步是不太現(xiàn)實的了。

  就在無計可施的時候,突然發(fā)現(xiàn)有一個叫CallContext的奇怪的類,藏匿在System.Runtime.Remoting.Messaging這個幾乎沒人用的namespace下面,當(dāng)然一開始我僅僅是被它的名稱所吸引,直譯過來不就是調(diào)用上下文嗎?感覺這個東西能有點作用。于是查閱了msdn,描述如下:

提供與執(zhí)行代碼路徑一起傳送的屬性集。無法繼承此類。

  一句廢話。。。看備注吧:

CallContext 是類似于方法調(diào)用的線程本地存儲區(qū)的專用集合對象,并提供對每個邏輯執(zhí)行線程都唯一的數(shù)據(jù)槽。數(shù)據(jù)槽不在其他邏輯線程上的調(diào)用上下文之間共享。當(dāng) CallContext 沿執(zhí)行代碼路徑往返傳播并且由該路徑中的各個對象檢查時,可將對象添加到其中。

當(dāng)對另一個 AppDomain 中的對象進(jìn)行遠(yuǎn)程方法調(diào)用時,CallContext 類將生成一個與該遠(yuǎn)程調(diào)用一起傳播的 LogicalCallContext 實例。只有公開 ILogicalThreadAffinative 接口并存儲在 CallContext 中的對象被在 LogicalCallContext 中傳播到 AppDomain 外部。不支持此接口的對象不在 LogicalCallContext 實例中與遠(yuǎn)程方法調(diào)用一起傳輸。

  似乎有那么點意思,不過邏輯線程的定義似乎有那么點模棱兩可,不過,也提到了一個接口ILogicalThreadAffinative,再看看這個接口定義了什么,一看成員定義。。。沒有成員。。。一個空接口,汗了一把,還是看看msdn上如何描述的吧:

標(biāo)記可以在 LogicalCallContext 中傳播到 AppDomain 外部的對象。

  強(qiáng)調(diào)了在remoting中的作用,再看看備注:

當(dāng)對另一個 AppDomain 中的對象進(jìn)行遠(yuǎn)程方法調(diào)用時,當(dāng)前的 CallContext 類生成一個將與該調(diào)用一起傳播到遠(yuǎn)程位置的 LogicalCallContext。只有公開 ILogicalThreadAffinative 接口并存儲在 CallContext 中的對象被傳播到 AppDomain 外部。不支持此接口的對象不在 LogicalCallContext 實例中與遠(yuǎn)程方法調(diào)用一起傳輸。

  也是強(qiáng)調(diào)在remoting中的作用,但是可以想象,基本上是CallContext中用了類似is ILogicalThreadAffinative的方式,來區(qū)別對待不同的對象,對于符合這個接口的將被放到LogicalCallContext,而不符合的另外處理。

  從文檔角度,似乎已經(jīng)沒有什么進(jìn)展了,這時候,突然想起來一個以前看過的很有趣的類型ExecutionContext,namespace是System.Threading,看起來就是多線程準(zhǔn)備的,不過,msdn上的例子就說了如何控制傳遞權(quán)限對象的問題,并沒有說到如何傳遞普通對象。

  一時想到所謂的LogicalCallContext會不會在ExecutionContext中存在哪?查了一下msdn,看到備注:

ExecutionContext 類為與執(zhí)行的邏輯線程相關(guān)的所有信息提供單個容器。這包括安全上下文、調(diào)用上下文和同步上下文。

ExecutionContext 類提供的功能讓戶代碼可以在用戶定義的異步點之間捕獲和傳輸此上下文。公共語言運行庫確保在托管進(jìn)程內(nèi)運行庫定義的異步點之間一致地傳輸 ExecutionContext。

執(zhí)行上下文是 COM 單元的托管等效項。在應(yīng)用程序域中,每當(dāng)傳輸線程時都必須傳輸整個執(zhí)行上下文。在由 Thread..::.Start 方法、大多數(shù)線程池操作和通過 Windows 消息泵進(jìn)行的 Windows 窗體線程封送處理所導(dǎo)致的傳輸過程中,將會出現(xiàn)這種情況。在不安全的線程池操作(如 UnsafeQueueUserWorkItem 方法)中不會出現(xiàn)這種情況,原因是不安全的線程池操作不會傳輸壓縮堆棧。每當(dāng)壓縮堆棧流動時,托管的主體、同步、區(qū)域設(shè)置和用戶上下文也隨之流動。ExecutionContext 類提供 Capture 和 CreateCopy 方法以獲取執(zhí)行上下文,并提供 Run 方法以設(shè)置當(dāng)前線程的執(zhí)行上下文。

與某個線程相關(guān)聯(lián)的 ExecutionContext 無法在另一個線程上進(jìn)行設(shè)置。嘗試這樣做會導(dǎo)致引發(fā)異常。若要將 ExecutionContext 從一個線程傳播到另一個線程,請制作 ExecutionContext 的副本。

ExecutionContext 在內(nèi)部存儲與 LogicalCallContext 相關(guān)聯(lián)的所有數(shù)據(jù)。這使得可以在復(fù)制和傳輸 ExecutionContext 時傳播 LogicalCallContext 數(shù)據(jù)。

  果然,ExecutionContext中有LogicalCallContext的數(shù)據(jù),并且很好的說明了,無論是Thread.Start還是用線程池大多數(shù)操作,ExecutionContext都會自動將這些數(shù)據(jù)傳遞給那些線程(關(guān)于ThreadPool.UnsafeQueueUerWorkItem方法相信用的人應(yīng)該不多),看起來演員們都到齊了,馬上可以演出一場多線程的好戲了。

  首先是起著關(guān)鍵作用ExectionContext,也許我們的代碼中沒必要出現(xiàn)它的身影,但是那僅僅是因為.net類庫的方法,為我們很好封裝了這個功能,沒有它,想在一個線程中把一個對象告訴另一個線程,就只有通過堆了。

  其次,LogicalCallContext,在眾多ExecutionContext傳播的對象中,很多是我們無法簡單的利用的(總不能為了傳播一個對象,去定義一個自定義的權(quán)限吧),而LogicalCallContext就是自定義對象的最好的載體。

  最后,剩下的問題就是如何讀寫這個LogicalCallContext的問題了,也就是終于輪到CallContext出場了。看一下CallContext為我們準(zhǔn)備了些什么方法:GetData, SetData, LogicalGetData, LogicalSetData, FreeNamedDataSlot, GetHeader, SetHeader以及HostContext屬性。

  第一焦點,當(dāng)然是GetData和SetData這兩個方法,做了個簡單的測試,發(fā)現(xiàn)這兩個方法,確實就是通過ILogicalThreadAffinative接口來決定是否要把對象發(fā)給新線程的,而刪除這個數(shù)據(jù)的方法就是FreeNamedDataSlot,現(xiàn)在只要為每一個要在多線程中共用的對象加上一個空接口,并且在多線程開始前在主線程中把對象設(shè)置進(jìn)去,然后在其他線程中再取出來就可以把問題搞定了。多線程部分結(jié)束后,不要忘記用FreeNamedDataSlot去刪除一下。

  不知道大家注意到?jīng)]有,出了GetData和SetData外,還有一對LogicalGetData和LogicalSetData,這兩個是干什么用的哪?是不是和LogicalCallContext的Logical有什么關(guān)系哪?

  又把前面的那個簡單的實驗做了一下,只不過用了LogicalGetData和LogicalSetData這兩個方法,結(jié)論是無論是否實現(xiàn)ILogicalThreadAffinative接口,對象都可以在新線程內(nèi)被訪問到,也就是說現(xiàn)在可以傳播任何數(shù)據(jù)給新線程,包括.net定義的string,int等基礎(chǔ)類型,這個方案已經(jīng)接近完美了。

  回過頭來看看我的任務(wù)吧,只需要修改AppContext.Current屬性的實現(xiàn),并且在多線程開始之前和之后做一個小小的處理,其他的組件就可以原封不動的并發(fā)的跑在各自的線程上。

  工作上的事情就到此為止了。

  在來說說CallContext.HostContext屬性是干什么的,經(jīng)過簡單的測試,發(fā)現(xiàn)在Asp.net程序中,這個HostContext里面放的就是HttpContext的實例,ms也夠偷懶的。其實ms只要做一個很小的修改,Asp.net的多線程就不用這么麻煩了,只需要HttpContext實現(xiàn)一下ILogicalThreadAffinative接口,無論新開多少個線程,到那邊都能訪問到HttpContext.Current了,當(dāng)然ms沒有這么做也是有原因的,一旦HttpContext被傳播到其他線程,那么asp.net就很難控制HttpContext對象的生命周期,而HttpContext對象又引用這HttpRequest對象,帶來的副作用可能要比想象的大得多。

轉(zhuǎn)載于:https://www.cnblogs.com/vwxyzh/archive/2009/02/21/1395416.html

總結(jié)

以上是生活随笔為你收集整理的CallContext和多线程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。