2010-12-19 79 views
44

我在網上看到它說我使用myThread.Join();當我想阻止我的線程,直到另一個線程完成。 (如果我有多個線程,我不知道這件事之一是什麼)。多線程:我什麼時候可以使用Join?

但是,一般來說,當我使用.Join()或條件對其有用時,我不會得到。任何人都可以向我解釋這個,就像我是四年級的學生一樣?很簡單的理解解釋會得到我的答案。

回答

49

比方說,你要開始一些工作線程執行某種計算,然後做一些事情之後所有的結果。

List<Thread> workerThreads = new List<Thread>(); 
List<int> results = new List<int>(); 

for (int i = 0; i < 5; i++) { 
    Thread thread = new Thread(() => { 
     Thread.Sleep(new Random().Next(1000, 5000)); 
     lock (results) { 
      results.Add(new Random().Next(1, 10)); 
     } 
    }); 
    workerThreads.Add(thread); 
    thread.Start(); 
} 

// Wait for all the threads to finish so that the results list is populated. 
// If a thread is already finished when Join is called, Join will return immediately. 
foreach (Thread thread in workerThreads) { 
    thread.Join(); 
} 

Debug.WriteLine("Sum of results: " + results.Sum()); 

噢,並且不使用隨機這樣,我只是想寫一個最小的,容易理解的例子。因爲種子是基於時鐘的,所以如果你創建新的Random實例的時間太近,它就不會是隨機的。

+1

你需要添加像'int值=我';'在你初始化一個新的Thread之前在foor-loop中。因爲'i'在線程啓動之前可能會增加,並且總和將是非確定性的。 – 2015-07-23 14:08:01

8

加入主要用於當您需要等待線程(或它們的一堆)在繼續執行代碼之前終止。

因爲這個原因,當你需要從線程執行中收集結果時,它也特別有用。

根據下面的Arafangion評論,如果您在創建線程後需要執行一些清洗/內務代碼,則加入線程也很重要。

+1

應該指出,在清理準備退出的過程時,這可能很重要。 – Arafangion 2010-12-19 23:46:56

+0

@Arafangion:對! – Lorenzo 2010-12-19 23:48:12

15

在下面的代碼片段,主線程調用Join(),導致其等待所有產生的線程來完成:

static void Main() 
{ 
    Thread regularThread = new Thread(ThreadMethod); 
    regularThread.Start(); 

    Thread regularThread2 = new Thread(ThreadMethod2); 
    regularThread2.Start(); 

    // Wait for spawned threads to end. 
    regularThread.Join(); 
    Console.WriteLine("regularThread returned."); 

    regularThread2.Join(); 
    Console.WriteLine("regularThread2 returned."); 
} 

請注意,如果你也轉動了從線程池中的線程(使用QueueUserWorkItem例如),Join不會等待該後臺線程。您需要實現一些其他機制,例如使用AutoResetEvent。

對於一個很好的介紹線程,建議閱讀喬阿爾巴哈利的免費Threading in C#

+1

感謝您的免費和有價值的電子書鏈接 – 2016-04-26 12:50:35

7

這是非常簡單的程序來演示線程Join的用法。請按照我的意見以獲得更好的理解。請按原樣寫入該程序。

using System; 
    using System.Threading; 


    namespace ThreadSample 
    { 
     class Program 
     { 
      static Thread thread1, thread2; 
      static int sum=0; 
      static void Main(string[] args) 
      { 
       start(); 
       Console.ReadKey(); 
      } 
      private static void Sample() { sum = sum + 1; } 
      private static void Sample2() { sum = sum + 10; } 

      private static void start() 
      {  
       thread1 = new Thread(new ThreadStart(Sample)); 
       thread2 = new Thread(new ThreadStart(Sample2)); 
       thread1.Start(); 
       thread2.Start(); 
      // thread1.Join(); 
      // thread2.Join(); 
       Console.WriteLine(sum); 
       Console.WriteLine(); 
      } 
     } 
} 

1。第一時間運行,因爲它是(帶註釋)然後結果將是0(初始值)或1(當線程1結束)或10(或線程完成)

2.Run與刪除評論thread1.Join()結果應該始終大於1。因爲thread1.Join()發射和線程1前應完成得到的總和。

3.Run與刪除所有評析結果應該是始終11

0

添加爲300ms的方法「樣本」從devopsEMK的帖子延遲和400ms的在「樣品2」的延遲將使得更容易理解。

通過這樣做,您可以觀察到通過從「thread1.Join();」中刪除註釋,線,主線程等待「線程1」完成並且只有在移動之後。

0

另一個例子,當你的工作線程假設從輸入流,而讀方法能夠永遠運行讀取,你想以某種方式避免這種情況 - 使用另一種看門狗線程應用超時:

// worker thread 
var worker = new Thread(() => { 
    Trace.WriteLine("Reading from stream"); 

    // here is the critical area of thread, where the real stuff happens 
    // Sleep is just an example, simulating any real operation 
    Thread.Sleep(10000); 

    Trace.WriteLine("Reading finished"); 
}) { Name = "Worker" }; 
Trace.WriteLine("Starting worker thread..."); 
worker.Start(); 

// watchdog thread 
ThreadPool.QueueUserWorkItem((o) => { 
    var timeOut = 5000; 
    if (!worker.Join(timeOut)) 
    { 
     Trace.WriteLine("Killing worker thread after " + timeOut + " milliseconds!"); 
     worker.Abort(); 
    } 
}); 
相關問題