2015-04-22 178 views
4

有了這個代碼:線程阻塞後等待

static void Main(string[] args) 
    { 
     Console.WriteLine("Main Thread Pre - " + GetNativeThreadId(System.Threading.Thread.CurrentThread)); 
     Task.Run(() => AsyncMethod()).Wait(); 
     Console.WriteLine("Main Thread Post - " + GetNativeThreadId(System.Threading.Thread.CurrentThread)); 
     Console.ReadKey(); 
    } 

    static async Task AsyncMethod() 
    { 
     Console.WriteLine("AsyncMethod Thread Pre - " + GetNativeThreadId(System.Threading.Thread.CurrentThread)); 
     await Task.Delay(4000).ConfigureAwait(false); 
     Console.WriteLine("AsyncMethod Thread Post - " + GetNativeThreadId(System.Threading.Thread.CurrentThread)); 
    } 

的輸出是:

Main Thread Pre - 8652 
AsyncMethod Thread Pre - 4764 
AsyncMethod Thread Post - 1768 
Main Thread Post - 8652 

使用併發可視化後可以看到4個第二延遲期間,螺紋4764是停留在同步。它最終在關機時被主線程解除封鎖。

一旦碰到await,不應將線程4764返回到ThreadPool? (這是說我不知道​​在Concurrency Visualizer裏面看起來會是什麼樣子)

+2

您可以演示任何類型的問題*沒有*訴諸併發可視化器? –

+0

不,我不能。我做了這個練習,看看在併發可視化器中看起來像是什麼樣的等待線程,並且一旦它等待,就很驚訝地看到它在同步類別中。要麼我對異步的理解不正確,要麼我誤解了併發可視化工具告訴我的內容。我想我只是在尋找確認線程4764實際上應該返回到ThreadPool的時候,它會等待。 – Cuthbert

+0

任務線程被延遲,但延遲調用仍然在內部運行一個計時器,因此正在工作。延遲不是調度延遲。 –

回答

4

不應該將線程4764返回到ThreadPool一旦它命中了等待?

是的。它是。

(話雖這麼說,我不知道是什麼樣子的併發可視化工具內)

這是很容易檢查。只需在線程池中明確執行一些代碼,並在可視化器不忙時看看該線程看起來像什麼。

例如:

ThreadPool.QueueUserWorkItem(o => 
    { 
     Console.WriteLine("worker: " + GetNativeThreadId(System.Threading.Thread.CurrentThread)); 
     Thread.Sleep(250); 
    }); 

(我加入了睡眠,因此更容易在可視化顯示爲已經做了:))。

當你這樣做時,你會發現它看起來就像你看到的一樣。 :)


當我跑這個時,線程池甚至使用它用於原始Task相同的工作線程。你可以看到一個線程池工作線程在Synchronization狀態下,它正在等待更多的工作。

這是有道理的。在抽象層面,線程池在做什麼?整個觀點是它有已經存在的線程。但你不希望那些線程實際上在那裏工作工作,除非他們有一些工作。這會無故地耗費CPU時間。相反,他們等待一個同步對象。

當某些事情(如Task)想要使用某個工作項時,它會對一個工作項進行排隊,然後線程池向該線程發出信號以表明它有某些工作要做。這會喚醒線程,執行它的工作,然後再次阻塞同步對象,等待其他事情的發生。

如果您檢查相關線程的調用堆棧,您會看到工作線程正在等待WaitForSingleObject()的調用,並且您會看到線程池最終使用ReleaseSemaphore()解鎖了線程。

這就像您看到的那樣,顯示爲線程池線程的Synchronization狀態。