Shai UI
Shai UI

Reputation: 51958

Multithreading: When would I use a Join?

I see online that it says I use myThread.Join(); when I want to block my thread until another thread finishes. (One of the things I don't get about this is what if I have multiple threads).

But generally, I just don't get when I'd use .Join() or a condition that it's useful for. Can anyone please explain this to me like I'm a fourth grader? Very simple explanation to understand will get my answer vote.

Upvotes: 70

Views: 89356

Answers (7)

Nayanajith
Nayanajith

Reputation: 645

Join will make sure that the treads above line is executed before executing lines below.

Upvotes: 5

Ladislav
Ladislav

Reputation: 349

Another example, when your worker thread let's say reads from an input stream while the read method can run forever and you want to somehow avoid this - by applying timeout using another watchdog thread:

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

Upvotes: 1

Paul S.
Paul S.

Reputation: 1

Adding a delay of 300ms in method "Sample" and a delay of 400ms in "Sample2" from devopsEMK's post would make it easier to understand.

By doing so you can observe that by removing the comment from "thread1.Join();" line, the main thread waits for the "thread1" to complete and only after moves on.

Upvotes: 0

Elshan
Elshan

Reputation: 7693

This is very simple program to demonstrate usage of Thread Join.Please follow my comments for better understanding.Write this program as it is.

    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.First time run as it is (with comments) : Then result will be 0(initial value) or 1(when thread 1 finished) or 10 (Or thread finished)

2.Run with removing comment thread1.Join() : Result should be always more than 1.because thread1.Join() fired and thread 1 should be finished before get the sum.

3.Run with removing all coments :Result should be always 11

Upvotes: 12

Mitch Wheat
Mitch Wheat

Reputation: 300719

In the following code snippet, the main thread calls Join() which causes it to wait for all spawned threads to finish:

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.");
}

Note that if you also spun up a thread from the thread pool (using QueueUserWorkItem for instance), Join would not wait for that background thread. You would need to implement some other mechanism such as using an AutoResetEvent.

For an excellent introduction to threading, I recommend reading Joe Albahari's free Threading in C#

Upvotes: 19

J.D.
J.D.

Reputation: 2134

Let's say you want to start some worker threads to perform some kind of calculation, and then do something afterwards with all the results.

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

Oh yeah, and don't use Random like that, I was just trying to write a minimal, easily understandable example. It ends up not really being random if you create new Random instances too close in time, since the seed is based on the clock.

Upvotes: 74

Lorenzo
Lorenzo

Reputation: 29427

Join is used mainly when you need to wait that a thread (or a bunch of them) will terminate before proceding with your code.

For this reason is also particular useful when you need to collect result from a thread execution.

As per the Arafangion comment below, it's also important to join threads if you need to do some cleaning/housekeeping code after having created a thread.

Upvotes: 11

Related Questions