Multithreading: When would I use a Join?

C#Multithreading

C# Problem Overview


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.

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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#

Solution 3 - C#

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

Solution 4 - C#

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.

Solution 5 - C#

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

Solution 6 - C#

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

Solution 7 - C#

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShai UIView Question on Stackoverflow
Solution 1 - C#J.D.View Answer on Stackoverflow
Solution 2 - C#Mitch WheatView Answer on Stackoverflow
Solution 3 - C#ElshanView Answer on Stackoverflow
Solution 4 - C#LorenzoView Answer on Stackoverflow
Solution 5 - C#NayanajithView Answer on Stackoverflow
Solution 6 - C#LadislavView Answer on Stackoverflow
Solution 7 - C#Paul S.View Answer on Stackoverflow