THX-1138
THX-1138

Reputation: 21750

Join threads from thread pool

I have 30+ tasks that can be executed in parallel.
I use ThreadPool for each task.
But parent-function should not return until all tasks has completed.

I need a thread sync handle that would release WaitOne when its count reaches 0. Something like:

foo.StartWith(myTasks.Count);
foreach (var task in myTasks) {
    ThreadPool.QueueUserWorkItem(state => { task(state); foo.Release(); });
}
foo.WaitOne();

Semaphore feels right, just can't figure out how to apply it here.

Upvotes: 3

Views: 9751

Answers (3)

YoniXw
YoniXw

Reputation: 585

According to this article: Overview of Synchronization Primitives

C# has a built-in type for this scenario, CountDownEvent: CountdownEvent Class

Or a similiar one: Barrier (.NET Framework)

For newer versions, use the TPL (Task Parallel Library) , and for this scenerio this code is relevant:

// Create an ActionBlock<int> object that prints its input
// and throws ArgumentOutOfRangeException if the input
// is less than zero.
var throwIfNegative = new ActionBlock<int>(n =>
{
   Console.WriteLine("n = {0}", n);
   if (n < 0)
   {
      throw new ArgumentOutOfRangeException();
   }
});

// Post values to the block.
throwIfNegative.Post(0);
throwIfNegative.Post(-1);
throwIfNegative.Post(1);
throwIfNegative.Post(-2);
throwIfNegative.Complete();

// Wait for completion in a try/catch block.
try
{
   throwIfNegative.Completion.Wait();
}
catch (AggregateException ae)
{
   // If an unhandled exception occurs during dataflow processing, all
   // exceptions are propagated through an AggregateException object.
   ae.Handle(e =>
   {
      Console.WriteLine("Encountered {0}: {1}", 
         e.GetType().Name, e.Message);
      return true;
   });
}

/* Output:
n = 0
n = -1
Encountered ArgumentOutOfRangeException: Specified argument was out of the range
 of valid values.
*/

from https://msdn.microsoft.com/en-us/library/hh228603.aspx

Upvotes: 0

spender
spender

Reputation: 120498

Joe Duffy wrote a great article on this sort of thing:

CLR Inside Out: 9 Reusable Parallel Data Structures and Algorithms

I'm eyballing the CountdownLatch as particularly appropriate for your requirements.

Upvotes: 0

Remus Rusanu
Remus Rusanu

Reputation: 294407

int running = myTasks.Count;
AutoResetEvent done = new AutoResetEvent(false);
foreach (var task in myTasks) {
    ThreadPool.QueueUserWorkItem(state => { 
    task(state); 
    if (0 == Interlocked.Decrement(ref running))
      done.Set ();
    });
}
done.WaitOne();

With C# 4.0 you can use the new CountdownEvent primitive.

Upvotes: 11

Related Questions