2011-12-06 52 views
4

從源代碼包含在TPL內聯像here閱讀後,我得到的印象是,以Task.Wait(通話)將啓動尚未開始(至少使用默認的調度器)的任務。但是,寫下如下快速演示:何時內聯任務發生?

var taskB = new Task(
() => 
     { 
     Console.WriteLine("In TaskB"); 
     System.Threading.Thread.Sleep(5000); 
     Console.WriteLine("Leaving TaskB"); 
     }); 

var taskA = new Task(
() => 
     { 
     Console.WriteLine("In TaskA"); 
     System.Threading.Thread.Sleep(500); 
     Console.WriteLine("Waiting on TaskB"); 
     taskB.Wait(); 
     Console.WriteLine("Leaving TaskA"); 
     }); 

taskA.Start(); 
taskA.Wait(); 

導致死鎖。 TaskA獲取任務B.Wait()行,但taskB永遠不會啓動。我沒有搞亂調度器或任何東西,所以我不確定爲什麼taskB上的.Wait()調用不會導致它啓動。

+4

您的示例代碼中沒有調用taskB.Start()。 –

回答

15

Wait()不會導致任務Start()。如果您在未啓動的任務上致電Wait(),它將等待它開始並完成,直至完成,等待超時或取消等待。由於您致電Wait()不包含取消標記或超時,因此完成該任務是無限的。

我認爲是一個從博客混淆你的是這一行:

然而,如果還沒有開始執行,等待或許能夠拉動 目標任務進行調度,以它爲排隊並執行 它在當前線程上內聯。

這裏的關鍵是那句「還沒有開始執行」。這並不意味着Start()不叫,但Start()調用,調度任務,並使它準備執行,但任務還沒有開始執行。

Start()是必要的安排執行任務,它不會立即開始執行。這是這個blurb的主要觀點。如果任務已準備好但未安排,則可以內聯。但它不會啓動一項甚至還沒有安排好的任務。

如果你看一下在MSDN TaskStatusSee here),你看到下面的值:

  • 創建
  • WaitingForActivation
  • WaitingToRun
  • 運行
  • WaitingForChildrenToComplete
  • RanToCompletion
  • 取消
  • 斷陷

當您創建任務(新的或工廠),它是在Created狀態。在這種狀態下,任何事情都不會發生。一旦它開始,然後移動到WaitingForActivation等等,在這一點上,直到它達到Running,根據該博客可能內聯它可能。

因此,長話短說,創建一個任務只是把它放在Created狀態,如果調用Wait(),它不會啓動它。合理?

2

該文章中提到的內聯不同於任務開始。等待任務不會啓動 - 這可以很容易地演示。剛剛嘗試以下操作:

namespace Test 
{ 
    using System; 
    using System.Threading.Tasks; 

    internal class TestCompile 
    { 
     private static void Main(string[] args) 
     { 
      Task t = new Task(() => Console.WriteLine("Executed!")); 
      t.Wait(5000); 
      Console.WriteLine("After wait..."); 
      Console.ReadKey(); 
     } 
    } 
} 

你會看到,永遠不會啓動任務...

task.Wait(),呼叫不會啓動任務。這將導致立即執行任務,如果當前線程(默認調度)的「內聯」:

  • 任務已經開始,但是...
  • 任務不是當前正在執行(因爲任務獲得由調度排隊)
  • 任務的調度程序(在建設創建)相同調度作爲當前一個
  • 任務不取消
  • 任務沒有故障

第三點是模糊的 - 它可以在不同的調度器上內聯執行,但是這需要其他調度器能夠立即執行它,所以它依賴於調度器是支持這一點的調度器。

相關問題