多线程:我什么时候使用Join?

时间:2010-12-19 23:35:23

标签: c# multithreading

我在网上看到它说当我想要阻止我的线程直到另一个线程完成时我使用myThread.Join();。 (如果我有多个线程,我不会得到的一件事就是这样。)

但一般情况下,我只是在使用.Join()或其有用的条件时才会得到。任何人都可以向我解释一下,就像我是四年级学生一样吗?理解的非常简单的解释将得到我的答案投票。

7 个答案:

答案 0 :(得分:64)

假设您想要启动一些工作线程来执行某种计算,然后在所有结果后做一些事情。

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,我只是想写一个简单易懂的例子。如果你在时间上创建新的Random实例,它最终不会是随机的,因为种子是基于时钟的。

答案 1 :(得分:18)

在下面的代码片段中,主线程调用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。

对于线程的精彩介绍,我建议阅读Joe Albahari的免费Threading in C#

答案 2 :(得分:12)

这是演示Thread 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.运行删除评论thread1.Join() 结果应始终大于1 。因为thread1.Join()被解雇且线程1应该完成在得到总和之前。

3.运行删除所有内容结果应始终为11

答案 3 :(得分:9)

Join主要用于在您使用代码进行处理之前需要等待一个线程(或一堆线程)终止的情况。

当您需要从线程执行中收集结果时,这个原因也特别有用。

根据下面的Arafangion评论,如果您在创建线程后需要执行一些清洁/内务代码,则加入线程也很重要。

答案 4 :(得分:3)

加入将确保在执行下面的行之前执行上面的踏板。

答案 5 :(得分:0)

在方法中添加300毫秒的延迟&#34;采样&#34; &#34; Sample2&#34;延迟400ms来自devopsEMK的帖子会让它更容易理解。

通过这样做,您可以通过删除&#34; thread1.Join();&#34;中的注释来观察行,主线程等待&#34; thread1&#34;完成后才开始行动。

答案 6 :(得分:0)

另一个例子,当你的工作线程让我们说输入流读取而read方法可以永远运行而你想以某种方式避免这种情况 - 通过使用另一个看门狗线程应用超时:

// 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();
    }
});