2010-12-19 55 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(); 
    } 
}); 
相关问题