[c#] How can I wait for a thread to finish with .NET?

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?

This question is related to c# multithreading

The answer is


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.


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.


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


Here's a simple example that waits for a tread to finish, within the same class. It also makes a call to another class in the same namespace. I included the "using" statements so it can execute as a Windows Forms form as long as you create button1.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace ClassCrossCall
{

    public partial class Form1 : Form
    {
        int number = 0; // This is an intentional problem, included
                        // for demonstration purposes
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button1.Text = "Initialized";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            button1.Text = "Clicked";
            button1.Refresh();
            Thread.Sleep(400);
            List<Task> taskList = new List<Task>();
            taskList.Add(Task.Factory.StartNew(() => update_thread(2000)));
            taskList.Add(Task.Factory.StartNew(() => update_thread(4000)));
            Task.WaitAll(taskList.ToArray());
            worker.update_button(this, number);
        }

        public void update_thread(int ms)
        {
            // It's important to check the scope of all variables
            number = ms; // This could be either 2000 or 4000. Race condition.
            Thread.Sleep(ms);
        }
    }

    class worker
    {
        public static void update_button(Form1 form, int number)
        {
            form.button1.Text = $"{number}";
        }
    }
}

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/


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


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


Try this:

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

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

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

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.