2011-12-18 15 views
0

.NET ThreadPool有a sample on MSDN。如果我運行這個代碼,輸出是完全不穩定的,有時候,我在控制檯上得到一個完全空的輸出。Console.WriteLine多線程輸出在.NET中爲空,x64

如果我添加一個Thread.Sleep()調用,即使只是幾個毫秒,輸出也沒問題。

AFAIK Console.WriteLine()是線程安全的,所以輸出應該總是在那裏。但它不是,至少不是我的i7 2600 x64編譯版本。很明顯,如果我添加一個斷點,一切都很好,但它讓我發瘋。

我添加了一個ConcurrentBag以確保東西在那裏,但是即使打印這些元素也是空的。再一次,如果我添加一個斷點,一切都很好。

{ 
    public class TaskInfo 
    { 
     public string m_text; 

      public int m_value; 
     public ConcurrentBag<int> m_bag; 
    public TaskInfo(string text, int value, ConcurrentBag<int> bag) 
    { 
     m_text = text; 
     m_value = value; 
     m_bag = bag; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Program p = new Program(); 
     p.Run(); 
    } 

    void Run() 
    { 
     ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>(); 
     for (int i = 0; i < 10; i++) 
     { 
      TaskInfo ti = new TaskInfo("Hello Thread", i, concurrentBag); 
      bool b = ThreadPool.QueueUserWorkItem(new WaitCallback(MyThreadFunction), ti); 
      if (!b) 
      { 
       Console.WriteLine("Damn!"); 
      } 
      //Thread.Sleep(5); 
     } 

     for (int j = 0; j < concurrentBag.Count; j++) 
     { 
      Console.WriteLine("This is in the bag: {0}", concurrentBag.ElementAt(j)); 
     } 
    } 

    static void MyThreadFunction(object stateInfo) 
    { 
     TaskInfo ti = (TaskInfo)stateInfo; 
     ti.m_bag.Add(ti.m_value); 
     Console.WriteLine(ti.m_text + ti.m_value.ToString()); 
    } 
} 

}

+0

你能鏈接到樣本嗎? – 2011-12-18 20:13:29

+0

http://msdn.microsoft.com/en-us/library/kbf0f1ct(v=vs.80).aspx – 2011-12-18 20:15:55

回答

1

我可以很好理解輸出可以是空的。

您在隊列上推送10個作業,然後立即開始消耗結果。並不是所有的工作都會完成,甚至還沒有任何工作已經開始。

而且在調試器中運行時,程序將終止,然後才能從MyThreadFunction中看到WrtieLine()。

+0

true。我剛剛閱讀了原始源代碼,並且還有一條評論和一個額外的sleep(),所以是的,主線程在後臺線程完成之前退出。謝謝! – 2011-12-18 20:20:51

0

是不是當你創建線程,你要加入他們(等到他們完成),直到您嘗試打印任何東西,他們「生產」?

如果不是,那麼您依賴的調度程序可以在Run的最後一個循環之前切換線程。如果沒有,最後一個循環在之前執行甚至開始任何線程。

另一方面,Thread.Sleep可以讓調度程序立即切換到其他線程,這可能就是爲什麼你看到裏面沒有Thread.Sleep問題。

1

這顯然是一個控制檯應用程序 - 在排隊完所有工作項之後,Run方法返回並且您的程序立即退出。它不會等待您的工作項目完成。至少,在運行後添加一個Thread.Sleep以允許線程池完成。

正確的做法是使用一個ManualResetEvent實例的數組,並等待它們全部由Set由每個工作線程。由於這是一個控制檯應用程序,因此除非您用[STAThread]修飾Main方法,否則將無法使用WaitHandle.WaitAll