Spawn Multiple Threads for work then wait until all finished

C#MultithreadingBackgroundworker

C# Problem Overview


just want some advice on "best practice" regarding multi-threading tasks.

as an example, we have a C# application that upon startup reads data from various "type" table in our database and stores the information in a collection which we pass around the application. this prevents us from hitting the database each time this information is required.

at the moment the application is reading data from 10 tables synchronously. i would really like to have the application read from each table in a different thread all running in parallel. the application would wait for all the threads to complete before continuing with the startup of the application.

i have looked into BackGroundWorker but just want some advice on accomplishing the above.

  1. Does the method sound logical in order to speed up the startup time of our application
  2. How can we best handle all the threads keeping in mind that each thread's work is independent of one another, we just need to wait for all the threads to complete before continuing.

i look forward to some answers

C# Solutions


Solution 1 - C#

My preference for this is to handle this via a single WaitHandle, and use Interlocked to avoid locking on a counter:

class Program
{
    static void Main(string[] args)
    {
        int numThreads = 10;
        ManualResetEvent resetEvent = new ManualResetEvent(false);
        int toProcess = numThreads;

        // Start workers.
        for (int i = 0; i < numThreads; i++)
        {
            new Thread(delegate()
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                // If we're the last thread, signal
                if (Interlocked.Decrement(ref toProcess) == 0)
                    resetEvent.Set();
            }).Start();
        }

        // Wait for workers.
        resetEvent.WaitOne();
        Console.WriteLine("Finished.");
    }
}

This works well, and scales to any number of threads processing, without introducing locking.

Solution 2 - C#

I like @Reed's solution. Another way to accomplish the same in .NET 4.0 would be to use a CountdownEvent.

class Program
{
    static void Main(string[] args)
    {
        var numThreads = 10;
        var countdownEvent = new CountdownEvent(numThreads);

        // Start workers.
        for (var i = 0; i < numThreads; i++)
        {
            new Thread(delegate()
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                // Signal the CountdownEvent.
                countdownEvent.Signal();
            }).Start();
        }

        // Wait for workers.
        countdownEvent.Wait();
        Console.WriteLine("Finished.");
    }
}

Solution 3 - C#

If you have more than 64 wait handles for an STA Thread as Mark says. you could create a list with your threads and wait for all to complete in a second loop.

//check that all threads have completed.
foreach (Thread thread in threadList)
{
     thread.Join();
                    
}  

Solution 4 - C#

If you're not on .NET 4.0 then you can use a List<ManualResetEvent>, one for each thread and Wait for them to be Set. To wait on multiple threads you could consider using WaitAll but watch out for the limit of 64 wait handles. If you need more than this, you can just loop over them and wait for each one individually.

If you want a faster startup exprience, you probably don't need to wait for all the data to be read during startup. Just display the GUI and any information that is missing can be shown greyed out with some sort of "Updating..." icon or similar. When the information comes in, just fire an event to update the GUI. There could be many operations that the user can begin to perform even before all the data from all tables is read in.

Solution 5 - C#

If you're feeling adventurous you can use C# 4.0 and the Task Parallel Library:

Parallel.ForEach(jobList, curJob => {
  curJob.Process()
});

Solution 6 - C#

Here are two patterns for waiting on multiple parallel operations. The trick is that you have to treat your main thread as if it were one of the parallel operations as well. Otherwise, there is a subtle race condition between the signalling of completion in the worker threads and the waiting on that signal from the main thread.

int threadCount = 1;
ManualResetEvent finished = new ManualResetEvent(false);
for (int i = 0; i < NUM_WORK_ITEMS; i++)
{
  Interlocked.Increment(ref threadCount); 
  ThreadPool.QueueUserWorkItem(delegate 
  { 
      try 
      { 
           // do work 
      } 
      finally 
      { 
          if (Interlocked.Decrement(ref threadCount) == 0) finished.Set();
      } 
  }); 
}
if (Interlocked.Decrement(ref threadCount) == 0) finished.Set();
finished.WaitOne(); 

As a personal preference I like using the CountdownEvent class to do the counting for me which is available in .NET 4.0.

var finished = new CountdownEvent(1);
for (int i = 0; i < NUM_WORK_ITEMS; i++)
{
  finished.AddCount();
  ThreadPool.QueueUserWorkItem(delegate 
  { 
      try 
      { 
           // do work 
      } 
      finally 
      { 
        finished.Signal();
      } 
  }); 
}
finished.Signal();
finished.Wait(); 

The examples above use the ThreadPool, but you can swap that for whatever threading mechanism you prefer.

Solution 7 - C#

Just for fun, what @Reed has done, with Monitor. :P

class Program
{
    static void Main(string[] args)
    {
        int numThreads = 10;
        int toProcess = numThreads;
        object syncRoot = new object();

        // Start workers.
        for (int i = 0; i < numThreads; i++)
        {
            new Thread(delegate()
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                // If we're the last thread, signal
                if (Interlocked.Decrement(ref toProcess) == 0)
                {
                    lock (syncRoot)
                    {
                        Monitor.Pulse(syncRoot);
                    }
                }
            }).Start();
        }

        // Wait for workers.
        lock (syncRoot)
        {
            if (toProcess > 0)
            {
                Monitor.Wait(syncRoot);
            }
        }

        Console.WriteLine("Finished.");
    }
}

Solution 8 - C#

Another possibility with TPL, assuming jobs is the collections of items to process, or subthreads to run:

Task.WaitAll(jobs
    .Select(job => TaskFactory.StartNew(() => /*run job*/))
    .ToArray());

Solution 9 - C#

Assuming the database reader threads return as soon as they're done, you can simply call Thread.Join on all ten threads in turn from the initiating thread.

Solution 10 - C#

If you are using .NET 3.5 or below, you can use an array of AsyncResult or BackgroundWorker and count how many threads have returned (just don't forget to decrease counter with interlocked operations) (see http://www.albahari.com/threading/ as a reference).

If you are using .NET 4.0 a parallel for is the simplest approach.

Solution 11 - C#

an easier method I like to use:

    private int ThreadsCount = 100; //initialize threads count
    private void button1_Click(object sender, EventArgs e)
    {   
        for (int i = 0; i < ThreadsCount; i++)
        {
            Thread t = new Thread(new ThreadStart(myMethod));
            t.IsBackground = true;
            t.Start(); 
        } 
    }

    private void myMethod()
    {
        //everytime a thread finishes executing decrease the threads count
        ThreadsCount = ThreadsCount - 1;

        if (ThreadsCount < 1)
        {
            //if all threads finished executing do whatever you wanna do here..
            MessageBox.Show("Finished Executing all threads!!!");
        }
    }

Solution 12 - C#

Posting to maybe help some others, spent quite a bit of time looking for a solution like what I came up with. So I took a little different approach. 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 was wanting 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.
}

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

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
QuestionpharocView Question on Stackoverflow
Solution 1 - C#Reed CopseyView Answer on Stackoverflow
Solution 2 - C#Jack LeitchView Answer on Stackoverflow
Solution 3 - C#Benjamin OrtuzarView Answer on Stackoverflow
Solution 4 - C#Mark ByersView Answer on Stackoverflow
Solution 5 - C#Benjamin OrtuzarView Answer on Stackoverflow
Solution 6 - C#Brian GideonView Answer on Stackoverflow
Solution 7 - C#Andras VassView Answer on Stackoverflow
Solution 8 - C#BartoszKPView Answer on Stackoverflow
Solution 9 - C#Marcelo CantosView Answer on Stackoverflow
Solution 10 - C#Danny VarodView Answer on Stackoverflow
Solution 11 - C#DesolatorView Answer on Stackoverflow
Solution 12 - C#AdamView Answer on Stackoverflow