2011-02-13 27 views
0

我一直在使用HTTP與客戶端進行通信的自定義多線程服務器。要創建新的線程,我一直在使用Task.Factory.StartNew()方法。爲了同步,我一直在使用ManualResetEvent對象。ManualResetEvent和任務問題

下面的代碼的本質:

namespace ThreadTest { 
    class Program {   
     private readonly ManualResetEvent _event = new ManualResetEvent(false); 

     public void Start() { 
      for (int i = 0; i < 100; i++) { 
       int num = i; 
       Task.Factory.StartNew(() => { 
        Console.WriteLine("Task {0} Started", num); 
        _event.WaitOne(); 
       }); 
      } 
     }  

     static void Main(string[] args) { 
      var test = new Program(); 
      test.Start(); 
      Console.ReadLine(); 
     } 
    } 
} 

在實際的代碼中,_event對象最終會叫上Set釋放等待任務。

我遇到的問題是,這段代碼在我的開發機器上運行正常(這是雙內核,每個內核有2個線程並使用MS .NET 4運行時),但不能在我的服務器上運行是單內核,每個內核有1個線程並使用Mono 2.8運行時)。我的機器上輸出是:

Task 0 Started 
Task 1 Started 
Task 3 Started 
Task 2 Started 
Task 4 Started 
Task 5 Started 
... 

雖然服務器輸出

Task 53 Started 

我的問題是:什麼是我誤解有關ManualResetEvent的或任務?爲什麼TaskFactory會繼續在雙核上執行任務,而不是在單核上執行任務?

更新:

我只是想在我的雙核心(每核心1個線程)的Mac筆記本電腦和我的輸出

Task 97 Started 
Task 1 Started 

然後什麼都沒有。我也在Mono上用我的開發機器(4線程)嘗試過它,並得到:

Task 99 Started 
Task 2 Started 
Task 98 Started 
Task 0 Started 

所以它看起來像一個單聲道的錯誤。

+0

一個問題是您對所有任務使用相同的事件。一旦任何單個任務設置了事件,所有其他等待都將立即落空。雖然這並不能解釋爲什麼你的服務器只顯示一個單一的任務開始。 – 2011-02-13 21:16:50

+0

@Jim Mischel:是的,在真實的代碼中,我有單獨的事件。我只是不明白爲什麼,在單線程機器上,我只能在一次啓動1個任務。 – cdmckay 2011-02-13 21:21:35

回答

0

您提交的代碼將永遠不會完成任何任務,因爲事件從不發送信號。最終,它將耗盡線程來分配並鎖定。這個問題真的是「當任何線程無法繼續執行時,任務並行庫在不同CPU配置下啓動的線程數有多少」,因爲這是您的代碼有效測量的內容。

任務並行庫的默認調度程序基於ThreadPool,該調度程序使用爬山算法來調整線程數以最大化工作項目完成率。該算法考慮了您擁有多少個核心。

有更好的方法來使用任務並行庫來安排一旦任務完成後發生的工作,而不是捆綁線程的方式,例如ContinueWith。你想用事件構造來實現什麼?

+0

代碼只是行爲的本質。正如它在問題中所說的,在真正的代碼中,我實際上在某個時候調用了`Set`並讓這些任務完成。 – cdmckay 2011-02-14 02:58:56