C#: Waiting for all threads to complete

C#Multithreading

C# Problem Overview


I'm running into a common pattern in the code that I'm writing, where I need to wait for all threads in a group to complete, with a timeout. The timeout is supposed to be the time required for all threads to complete, so simply doing thread.Join(timeout) for each thread won't work, since the possible timeout is then timeout * numThreads.

Right now I do something like the following:

var threadFinishEvents = new List<EventWaitHandle>();

foreach (DataObject data in dataList)
{
    // Create local variables for the thread delegate
    var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
    threadFinishEvents.Add(threadFinish);

    var localData = (DataObject) data.Clone();
    var thread = new Thread(
        delegate()
        {
            DoThreadStuff(localData);
            threadFinish.Set();
        }
    );
    thread.Start();
}

Mutex.WaitAll(threadFinishEvents.ToArray(), timeout);

However, it seems like there should be a simpler idiom for this sort of thing.

C# Solutions


Solution 1 - C#

I still think using Join is simpler. Record the expected completion time (as Now+timeout), then, in a loop, do

if(!thread.Join(End-now))
    throw new NotFinishedInTime();

Solution 2 - C#

With .NET 4.0 I find System.Threading.Tasks a lot easier to work with. Here's spin-wait loop which works reliably for me. It blocks the main thread until all the tasks complete. There's also Task.WaitAll, but that hasn't always worked for me.

		for (int i = 0; i < N; i++)
	    {
	    	tasks[i] = Task.Factory.StartNew(() =>
	    	{				
	    		 DoThreadStuff(localData);
	    	});
    	}
    	while (tasks.Any(t => !t.IsCompleted)) { } //spin wait

Solution 3 - C#

Off the top of my head, why don't you just Thread.Join(timeout) and remove the time it took to join from the total timeout?

// pseudo-c#:

TimeSpan timeout = timeoutPerThread * threads.Count();

foreach (Thread thread in threads)
{
    DateTime start = DateTime.Now;
    
    if (!thread.Join(timeout))
        throw new TimeoutException();

    timeout -= (DateTime.Now - start);
}

Edit: code is now less pseudo. don't understand why you would mod an answer -2 when the answer you modded +4 is exactly the same, only less detailed.

Solution 4 - C#

Since the question got bumped I will go ahead and post my solution.

using (var finished = new CountdownEvent(1)) 
{ 
  for (DataObject data in dataList) 
  {   
    finished.AddCount();
    var localData = (DataObject)data.Clone(); 
    var thread = new Thread( 
        delegate() 
        {
          try
          {
            DoThreadStuff(localData); 
            threadFinish.Set();
          }
          finally
          {
            finished.Signal();
          }
        } 
    ); 
    thread.Start(); 
  }  
  finished.Signal(); 
  finished.Wait(YOUR_TIMEOUT); 
} 

Solution 5 - C#

This doesn't answer the question (no timeout), but I've made a very simple extension method to wait all threads of a collection:

using System.Collections.Generic;
using System.Threading;
namespace Extensions
{
	public static class ThreadExtension
	{
		public static void WaitAll(this IEnumerable<Thread> threads)
		{
			if(threads!=null)
			{
				foreach(Thread thread in threads)
				{ thread.Join(); }
			}
		}
	}
}

Then you simply call:

List<Thread> threads=new List<Thread>();
//Add your threads to this collection
threads.WaitAll();

Solution 6 - C#

This may not be an option for you, but if you can use the Parallel Extension for .NET then you could use Tasks instead of raw threads and then use Task.WaitAll() to wait for them to complete.

Solution 7 - C#

I was tying to figure out how to do this but i could not get any answers from google. I know this is an old thread but here was my solution:

Use the following class:

class ThreadWaiter
    {
        private int _numThreads = 0;
        private int _spinTime;

        public ThreadWaiter(int SpinTime)
        {
            this._spinTime = SpinTime;
        }

        public void AddThreads(int numThreads)
        {
            _numThreads += numThreads;
        }

        public void RemoveThread()
        {
            if (_numThreads > 0)
            {
                _numThreads--;
            }
        }

        public void Wait()
        {
            while (_numThreads != 0)
            {
                System.Threading.Thread.Sleep(_spinTime);
            }
        }
    }
  1. Call Addthreads(int numThreads) before executing a thread(s).
  2. Call RemoveThread() after each one has completed.
  3. Use Wait() at the point that you want to wait for all the threads to complete before continuing

Solution 8 - C#

I read the book C# 4.0: The Complete Reference of Herbert Schildt. The author use join to give a solution :

class MyThread
    {
        public int Count;
        public Thread Thrd;
        public MyThread(string name)
        {
            Count = 0;
            Thrd = new Thread(this.Run);
            Thrd.Name = name;
            Thrd.Start();
        }
        // Entry point of thread.
        void Run()
        {
            Console.WriteLine(Thrd.Name + " starting.");
            do
            {
                Thread.Sleep(500);
                Console.WriteLine("In " + Thrd.Name +
                ", Count is " + Count);
                Count++;
            } while (Count < 10);
            Console.WriteLine(Thrd.Name + " terminating.");
        }
    }
    // Use Join() to wait for threads to end.
    class JoinThreads
    {
        static void Main()
        {
            Console.WriteLine("Main thread starting.");
            // Construct three threads.
            MyThread mt1 = new MyThread("Child #1");
            MyThread mt2 = new MyThread("Child #2");
            MyThread mt3 = new MyThread("Child #3");
            mt1.Thrd.Join();
            Console.WriteLine("Child #1 joined.");
            mt2.Thrd.Join();
            Console.WriteLine("Child #2 joined.");
            mt3.Thrd.Join();
            Console.WriteLine("Child #3 joined.");
            Console.WriteLine("Main thread ending.");
            Console.ReadKey();
        }
    }

Solution 9 - C#

Possible solution:

var tasks = dataList
    .Select(data => Task.Factory.StartNew(arg => DoThreadStuff(data), TaskContinuationOptions.LongRunning | TaskContinuationOptions.PreferFairness))
    .ToArray();

var timeout = TimeSpan.FromMinutes(1);
Task.WaitAll(tasks, timeout);

Assuming dataList is the list of items and each item needs to be processed in a separate thread.

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
QuestionJSBձոգչView Question on Stackoverflow
Solution 1 - C#Martin v. LöwisView Answer on Stackoverflow
Solution 2 - C#T. WebsterView Answer on Stackoverflow
Solution 3 - C#Omer van KloetenView Answer on Stackoverflow
Solution 4 - C#Brian GideonView Answer on Stackoverflow
Solution 5 - C#VincentView Answer on Stackoverflow
Solution 6 - C#Jon NortonView Answer on Stackoverflow
Solution 7 - C#DylanView Answer on Stackoverflow
Solution 8 - C#Bùi Công GiaoView Answer on Stackoverflow
Solution 9 - C#Alex AzaView Answer on Stackoverflow