How can I wait for a thread to finish with .NET?

C#Multithreading

C# Problem Overview


I've never really used threading before in C# where I need to have two threads, as well as the main UI thread. Basically, I have the following.

public void StartTheActions()
{
  // Starting thread 1....
  Thread t1 = new Thread(new ThreadStart(action1));
  t1.Start();

  // Now, I want for the main thread (which is calling `StartTheActions` method)
  // to wait for `t1` to finish. I've created an event in `action1` for this.
  // The I wish `t2` to start...

  Thread t2 = new Thread(new ThreadStart(action2));
  t2.Start();
}

So, essentially, how can I have a thread wait for another one to finish? What is the best way to do this?

C# Solutions


Solution 1 - C#

I can see five options available:

1. Thread.Join

As with Mitch's answer. But this will block your UI thread, however you get a Timeout built in for you.


2. Use a WaitHandle

ManualResetEvent is a WaitHandle as jrista suggested.

One thing to note is if you want to wait for multiple threads: WaitHandle.WaitAll() won't work by default, as it needs an MTA thread. You can get around this by marking your Main() method with MTAThread - however this blocks your message pump and isn't recommended from what I've read.


3. Fire an event

See this page by Jon Skeet about events and multi-threading. It's possible that an event can become unsubcribed between the if and the EventName(this,EventArgs.Empty) - it's happened to me before.

(Hopefully these compile, I haven't tried)

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker();
        worker.ThreadDone += HandleThreadDone;

        Thread thread1 = new Thread(worker.Run);
        thread1.Start();

        _count = 1;
    }

    void HandleThreadDone(object sender, EventArgs e)
    {
        // You should get the idea this is just an example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();
            worker.ThreadDone += HandleThreadDone;

            Thread thread2 = new Thread(worker.Run);
            thread2.Start();

            _count++;
        }
    }

    class ThreadWorker
    {
        public event EventHandler ThreadDone;

        public void Run()
        {
            // Do a task

            if (ThreadDone != null)
                ThreadDone(this, EventArgs.Empty);
        }
    }
}

4. Use a delegate
public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker();

        Thread thread1 = new Thread(worker.Run);
        thread1.Start(HandleThreadDone);

        _count = 1;
    }

    void HandleThreadDone()
    {
        // As before - just a simple example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();

            Thread thread2 = new Thread(worker.Run);
            thread2.Start(HandleThreadDone);

            _count++;
        }
    }

    class ThreadWorker
    {
        // Switch to your favourite Action<T> or Func<T>
        public void Run(object state)
        {
            // Do a task

            Action completeAction = (Action)state;
            completeAction.Invoke();
        }
    }
}

If you do use the _count method, it might be an idea (to be safe) to increment it using

Interlocked.Increment(ref _count)

I'd be interested to know the difference between using delegates and events for thread notification, the only difference I know are events are called synchronously.


5. Do it asynchronously instead

The answer to this question has a very clear description of your options with this method.


Delegate/Events on the wrong thread

The event/delegate way of doing things will mean your event handler method is on thread1/thread2 not the main UI thread, so you will need to switch back right at the top of the HandleThreadDone methods:

// Delegate example
if (InvokeRequired)
{
    Invoke(new Action(HandleThreadDone));
    return;
}

Solution 2 - C#

Add

t1.Join();    // Wait until thread t1 finishes

after you start it, but that won't accomplish much as it's essentialy the same result as running on the main thread!

I can highly recommended reading Joe Albahari's Threading in C# free e-book, if you want to gain an understanding of threading in .NET.

Solution 3 - C#

If using from .NET 4 this sample can help you:

class Program
{
    static void Main(string[] args)
    {
        Task task1 = Task.Factory.StartNew(() => doStuff());
        Task task2 = Task.Factory.StartNew(() => doStuff());
        Task task3 = Task.Factory.StartNew(() => doStuff());
        Task.WaitAll(task1, task2, task3);
        Console.WriteLine("All threads complete");
    }

    static void doStuff()
    {
        // Do stuff here
    }
}

From: Create multiple threads and wait all of them to complete

Solution 4 - C#

The previous two answers are great and will work for simple scenarios. There are other ways to synchronize threads, however. The following will also work:

public void StartTheActions()
{
    ManualResetEvent syncEvent = new ManualResetEvent(false);

    Thread t1 = new Thread(
        () =>
        {
            // Do some work...
            syncEvent.Set();
        }
    );
    t1.Start();

    Thread t2 = new Thread(
        () =>
        {
            syncEvent.WaitOne();

            // Do some work...
        }
    );
    t2.Start();
}

ManualResetEvent is one of the various WaitHandle's that the .NET framework has to offer. They can provide much richer thread synchronization capabilities than the simple, but very common tools like lock()/Monitor, Thread.Join, etc.

They can also be used to synchronize more than two threads, allowing complex scenarios such as a 'master' thread that coordinates multiple 'child' threads, multiple concurrent processes that are dependent upon several stages of each other to be synchronized, etc.

Solution 5 - C#

You want the Thread.Join() method, or one of its overloads.

Solution 6 - C#

I would have your main thread pass a callback method to your first thread, and when it's done, it will invoke the callback method on the mainthread, which can launch the second thread. This keeps your main thread from hanging while its waiting for a Join or Waithandle. Passing methods as delegates is a useful thing to learn with C# anyway.

Solution 7 - C#

I took a little different approach. There is a counter option in previous answers, and I just applied it a bit differently. I was spinning off numerous threads and incremented a counter and decremented a counter as a thread started and stopped. Then in the main method I wanted to pause and wait for threads to complete I did.

while (threadCounter > 0)
{
    Thread.Sleep(500); // Make it pause for half second so that we don’t spin the CPU out of control.
}

This is documented in my blog post: http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/

Solution 8 - C#

Try this:

List<Thread> myThreads = new List<Thread>();

foreach (Thread curThread in myThreads)
{
    curThread.Start();
}

foreach (Thread curThread in myThreads)
{
    curThread.Join();
}

Solution 9 - C#

When I want the UI to be able to update its display while waiting for a task to complete, I use a while-loop that tests IsAlive on the thread:

	Thread t = new Thread(() => someMethod(parameters));
	t.Start();
	while (t.IsAlive)
	{
		Thread.Sleep(500);
		Application.DoEvents();
	}

Solution 10 - C#

This implementation is a little different from @jrista's example based on ManualResetEvent as it shows how the various options are like a red or green traffic light.

    public System.Threading.AutoResetEvent thread1done = new System.Threading.AutoResetEvent(false);

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
	{
		thread1done.Set(); //set traffic light to green before threading
		StartTheActions();
	}

	public void StartTheActions()
	{
		Thread t1 = new Thread(action1);

		t1.Start();
		thread1done.WaitOne(); //traffic light is red, until thread1done.Set inside action1()

		Thread t2 = new Thread(action2);
		t2.Start();
	}
	public void action1()
	{
		Thread.Sleep(5000);
		//.... do some work
		thread1done.Set(); //work is done, set traffic light to green at thread1done.WaitOne()
	}
	public void action2()
	{
		MessageBox.Show("Now processing action2");
	}

Solution 11 - C#

Another method is using lock(someObject) and Monitor.Wait(someObject[,timeout]) in one thread and lock(someObject) and Monitor.Pulse(someObject) in another thread. SomeObject has to be the same instance of a class in all 4 calls. SomeObject can't be a struct.

The first thread locks someObject and then calls Monitor.Wait() which releases the lock, so the second thread can lock someObject. When the second thread is finished it calls Monitor.Pulse(), and then the first thread's Monitor.Wait() ends.

Example: someObject is a queue, the first threads waits for the second to put an object in the queue and then dequeues that object.

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
QuestionMaxim ZaslavskyView Question on Stackoverflow
Solution 1 - C#Chris SView Answer on Stackoverflow
Solution 2 - C#Mitch WheatView Answer on Stackoverflow
Solution 3 - C#Sayed Abolfazl FatemiView Answer on Stackoverflow
Solution 4 - C#jristaView Answer on Stackoverflow
Solution 5 - C#Daniel PrydenView Answer on Stackoverflow
Solution 6 - C#Ed PowerView Answer on Stackoverflow
Solution 7 - C#AdamView Answer on Stackoverflow
Solution 8 - C#Wendell TagsipView Answer on Stackoverflow
Solution 9 - C#Mark EmersonView Answer on Stackoverflow
Solution 10 - C#user16594857View Answer on Stackoverflow
Solution 11 - C#SijeDeHaanView Answer on Stackoverflow