callcontext和多執行緒
就在無計可施的時候,突然發現有乙個叫callcontext的奇怪的類,藏匿在system.runtime.remoting.messaging這個幾乎沒人用的namespace下面,當然一開始我僅僅是被它的名稱所吸引,直譯過來不就是呼叫上下文嗎?感覺這個東西能有點作用。於是查閱了msdn,描述如下:
提供與執行**路徑一起傳送的屬性集。無法繼承此類。
一句廢話。。。看備註吧:
callcontext是類似於方法呼叫的執行緒本地儲存區的專用集合物件,並提供對每個邏輯執行執行緒都唯一的資料槽。資料槽不在其他邏輯執行緒上的呼叫上下文之間共享。當callcontext沿執行**路徑往返傳播並且由該路徑中的各個物件檢查時,可將物件新增到其中。
似乎有那麼點意思,不過邏輯執行緒的定義似乎有那麼點模稜兩可,不過,也提到了乙個介面ilogicalthreadaffinative,再看看這個介面定義了什麼,一看成員定義。。。沒有成員。。。乙個空介面,汗了一把,還是看看msdn上如何描述的吧:
強調了在remoting中的作用,再看看備註:
也是強調在remoting中的作用,但是可以想象,基本上是callcontext中用了類似is ilogicalthreadaffinative的方式,來區別對待不同的物件,對於符合這個介面的將被放到logicalcallcontext,而不符合的另外處理。
從文件角度,似乎已經沒有什麼進展了,這時候,突然想起來乙個以前看過的很有趣的型別executioncontext,namespace是system.threading,看起來就是多執行緒準備的,不過,msdn上的例子就說了如何控制傳遞許可權物件的問題,並沒有說到如何傳遞普通物件。
一時想到所謂的logicalcallcontext會不會在executioncontext中存在哪?查了一下msdn,看到備註:
executioncontext 類為與執行的邏輯執行緒相關的所有資訊提供單個容器。這包括安全上下文、呼叫上下文和同步上下文。
executioncontext 類提供的功能讓戶**可以在使用者定義的非同步點之間捕獲和傳輸此上下文。公共語言執行庫確保在託管程序內執行庫定義的非同步點之間一致地傳輸 executioncontext。
執行上下文是 com 單元的託管等效項。在應用程式域中,每當傳輸線程時都必須傳輸整個執行上下文。在由 thread..::.start
方法、大多數執行緒池操作和通過 windows 訊息幫浦進行的 windows 窗體執行緒封送處理所導致的傳輸過程中,將會出現這種情況。在不安全的執行緒池操作(如 unsafequeueuserworkitem
方法)中不會出現這種情況,原因是不安全的執行緒池操作不會傳輸壓縮堆疊。每當壓縮堆疊流動時,託管的主體、同步、區域設定和使用者上下文也隨之流動。executioncontext 類提供 capture
和 createcopy
方法以獲取執行上下文,並提供 run
方法以設定當前執行緒的執行上下文。
與某個執行緒相關聯的 executioncontext 無法在另乙個執行緒上進行設定。嘗試這樣做會導致引發異常。若要將 executioncontext 從乙個執行緒傳播到另乙個執行緒,請製作 executioncontext 的副本。
executioncontext 在內部儲存與 logicalcallcontext
相關聯的所有資料。這使得可以在複製和傳輸 executioncontext 時傳播 logicalcallcontext
資料。果然,executioncontext中有logicalcallcontext的資料,並且很好的說明了,無論是thread.start還是用執行緒池大多數操作,executioncontext都會自動將這些資料傳遞給那些執行緒(關於threadpool.unsafequeueuerworkitem方法相信用的人應該不多),看起來演員們都到齊了,馬上可以演出一場多執行緒的好戲了。
首先是起著關鍵作用exectioncontext,也許我們的**中沒必要出現它的身影,但是那僅僅是因為.net類庫的方法,為我們很好封裝了這個功能,沒有它,想在乙個執行緒中把乙個物件告訴另乙個執行緒,就只有通過堆了。
其次,logicalcallcontext,在眾多executioncontext傳播的物件中,很多是我們無法簡單的利用的(總不能為了傳播乙個物件,去定義乙個自定義的許可權吧),而logicalcallcontext就是自定義物件的最好的載體。
最後,剩下的問題就是如何讀寫這個logicalcallcontext的問題了,也就是終於輪到callcontext出場了。看一下callcontext為我們準備了些什麼方法:getdata, setdata, logicalgetdata, logicalsetdata, freenameddataslot, getheader, setheader以及hostcontext屬性。
第一焦點,當然是getdata和setdata這兩個方法,做了個簡單的測試,發現這兩個方法,確實就是通過ilogicalthreadaffinative介面來決定是否要把物件發給新執行緒的,而刪除這個資料的方法就是freenameddataslot,現在只要為每乙個要在多執行緒中共用的物件加上乙個空介面,並且在多執行緒開始前在主線程中把物件設定進去,然後在其他執行緒中再取出來就可以把問題搞定了。多執行緒部分結束後,不要忘記用freenameddataslot去刪除一下。
不知道大家注意到沒有,出了getdata和setdata外,還有一對logicalgetdata和logicalsetdata,這兩個是幹什麼用的哪?是不是和logicalcallcontext的logical有什麼關係哪?
又把前面的那個簡單的實驗做了一下,只不過用了logicalgetdata和logicalsetdata這兩個方法,結論是無論是否實現ilogicalthreadaffinative介面,物件都可以在新執行緒內被訪問到,也就是說現在可以傳播任何資料給新執行緒,包括.net定義的string,int等基礎型別,這個方案已經接近完美了。
工作上的事情就到此為止了。
在來說說callcontext.hostcontext屬性是幹什麼的,經過簡單的測試,發現在asp.net程式中,這個hostcontext裡面放的就是httpcontext的例項,ms也夠偷懶的。其實ms只要做乙個很小的修改,asp.net的多執行緒就不用這麼麻煩了,只需要httpcontext實現一下ilogicalthreadaffinative介面,無論新開多少個執行緒,到那邊都能訪問到httpcontext.current了,當然ms沒有這麼做也是有原因的,一旦httpcontext被傳播到其他執行緒,那麼asp.net就很難控制httpcontext物件的生命週期,而httpcontext物件又引用這httprequest物件,帶來的***可能要比想象的大得多
CallContext和多執行緒
就在無計可施的時候,突然發現有乙個叫callcontext的奇怪的類,藏匿在system.runtime.remoting.messaging這個幾乎沒人用的namespace下面,當然一開始我僅僅是被它的名稱所吸引,直譯過來不就是呼叫上下文嗎?感覺這個東西能有點作用。於是查閱了msdn,描述如下 ...
多執行緒和執行緒池
執行緒的建立 執行 銷毀三個階段中,只有執行狀態才在處理任務,所以我們希望花在建立和銷毀執行緒的資源越少越好,於是,為了省去了頻繁建立和銷毀執行緒的麻煩,就有了執行緒池。在開始就建立一定量的執行緒,批量處理任務,等不再需要執行緒的時候再銷毀。一.執行緒池簡介 二.執行緒池優缺點 執行緒池缺點 1 建...
多執行緒和同步
分幾種情況 1.其他方法前是否加了synchronized關鍵字,如果沒加,則能。2.如果這個方法內部呼叫了wait,則可以進入其他synchronized方法。3.如果其他個方法都加了synchronized關鍵字,並且內部沒有呼叫wait,則不能。4.如果其他方法是static,它用的同步鎖是當...