簡單看看ThreadPool的原始碼以及從中看出執行緒間傳值的另一種方法

一線碼農發表於2014-11-06

 

   這幾天太忙沒時間寫部落格,今天回家就簡單的看了下ThreadPool的原始碼,發現有一個好玩的東西,叫做”執行上下文“,拽名叫做:”ExecutionContext“。

 

一:ThreadPool的大概流程。

 

第一步:它會呼叫底層一個helper方法。

 

第二步:走進這個helper方法,我們會發現有一個佇列,並且這個佇列的item必須是QueueUserWorkItemCallback的例項,然後這就激發了我的

           興趣,看看QueueUserWorkItemCallback到底都有些什麼?

 

第三步:走到QueueUserWorkItemCallback例項的時候,會依次把callback,state引數給當前類的欄位,並且有一個好玩的地方的就是根據

     ExecutionContext.IsFlowSuppressed()來判斷要不要把”當前執行緒的上下文“給”呼叫執行緒“?這個放在後面講,然後我們看到了一

    個 IThreadPoolWorkItem.ExecuteWorkItem()方法,裡面有ContextCallback委託的呼叫,也許這個就是佇列中每一項中要呼叫

    的方法。

 

第四步:然後我們再回到第二步中的 ThreadPoolGlobals.workQueue.Enqueue(callback, true)方法進去看看,並且我們的callback,state都被封裝成了

      QueueUserWorkItemCallback放到佇列中了,從這個Enqueue方法中,我們看到了一個this.EnsureThreadRequested(),走到方法裡面去了

    之後,這時候急迫想去看ThreadPool.RequestWorkerThread()方法,但它是個extern方法,不過從名字上看就是請求工作執行緒去執行,所以並

    沒有真實的發現到所謂的執行緒池這個東西。(由於不能窺全貌,可能有些說的不太對)

 

好了,上面的剖析大概就這樣了,其實所有的方法都封裝成了底層的一個類放在一個佇列中,應該是用上面的for來挑選空閒的工作執行緒去執行我們

的任務,裡面還有很多程式碼,比較複雜,一時也看不懂什麼。

 

二:執行上下文

  剛才第三步說到了”執行上下文“,看到這個方法裡面有一個if條件,然後看到有一個 ExecutionContext.IsFlowSuppressed()方法,從名字上

就可以看出叫”阻止流動“,如果為否的話,就用Capture來抓當前執行緒的”上下文資訊“,然後我們就順藤摸瓜的往下看,從這個方法來看,我們依次

去抓取呼叫執行緒的”安全設定“,”宿主設定“,”同步資訊“,“邏輯呼叫”,並且可以看到logicalCallContext有值的話,會做一個copy的操作。

 

其實這個logicalCallContext非常有意思,裡面是一個KV結構,原始碼裡面也說了,只要我不IsFlowSuppressed,那麼主執行緒的上下文會flow到

工作執行緒,那麼logicalCallContext怎麼設定呢?其實在C#裡面的CallContext裡面的LogicalSetData和LogicalGetData就可以做這些事情。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             CallContext.LogicalSetData("name", "ctrip");
 6 
 7             Thread.CurrentThread.IsBackground = true;
 8 
 9             ThreadPool.QueueUserWorkItem((o) =>
10             {
11                 var t = Thread.CurrentThread.ManagedThreadId;
12 
13                 var result = CallContext.LogicalGetData("name");
14 
15                 Console.WriteLine("我是工作執行緒: Name:" + result);
16 
17             });
18 
19             Console.Read();
20         }
21     }

 

可以看到我在主執行緒設定的值被工作執行緒讀到了,是不是很有意思,給我們執行緒間傳值提供了另一種方法,剛才我們也看到,一旦IsFlowSuppressed

了,那麼context就返回null,也就阻止了將logicCallContext的資訊傳遞給工作執行緒,可以用ExecutionContext.SuppressFlow()做到,下面具體

看一看。

 1   class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             CallContext.LogicalSetData("name", "ctrip");
 6 
 7             //阻止logical資料流動
 8             ExecutionContext.SuppressFlow();
 9 
10             Thread.CurrentThread.IsBackground = true;
11 
12             ThreadPool.QueueUserWorkItem((o) =>
13             {
14                 var t = Thread.CurrentThread.ManagedThreadId;
15 
16                 var result = CallContext.LogicalGetData("name");
17 
18                 Console.WriteLine("我是工作執行緒: Name:" + result);
19 
20             });
21 
22             Console.Read();
23         }
24     }

 

現在結論也出來了,去Capture主執行緒的上下文是需要很多的程式碼量,所以如果工作執行緒用不到主執行緒的這些資訊,那麼你應該做到顯示關閉,這樣

對工作執行緒的效能來說有很大的好處。

 

相關文章