Wait for QueueUserWorkItem to Complete
Solution 1
You could use events to sync. Like this:
private static ManualResetEvent resetEvent = new ManualResetEvent(false);
public static void Main()
{
ThreadPool.QueueUserWorkItem(arg => DoWork());
resetEvent.WaitOne();
}
public static void DoWork()
{
Thread.Sleep(5000);
resetEvent.Set();
}
If you don't want to embed event set into your method, you could do something like this:
var resetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(
arg =>
{
DoWork();
resetEvent.Set();
});
resetEvent.WaitOne();
For multiple items:
var events = new List<ManualResetEvent>();
foreach(var job in jobs)
{
var resetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(
arg =>
{
DoWork(job);
resetEvent.Set();
});
events.Add(resetEvent);
}
WaitHandle.WaitAll(events.ToArray());
Solution 2
The best way to do this is to use the CountdownEvent
class. This is a fairly well established pattern and is about as scalable as it gets.
using (var finished = new CountdownEvent(1))
{
foreach (var workitem in workitems)
{
var capture = workitem; // Used to capture the loop variable in the lambda expression.
finished.AddCount(); // Indicate that there is another work item.
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
ProcessWorkItem(capture);
}
finally
{
finished.Signal(); // Signal that the work item is complete.
}
}, null);
}
finished.Signal(); // Signal that queueing is complete.
finished.Wait(); // Wait for all work items to complete.
}
Solution 3
You can use .NET's Barrier class to achieve this.
Barrier barrier = new Barrier(3);
for(int i = 0; i < 2; i++)
{
ThreadPool.QueueUserWorkItem(
(state) =>
{
foo();
barrier.SignalAndWait();
}, null);
}
barrier.SignalAndWait();
Related videos on Youtube
PedroC88
Project manager and developer, usually dance to the music in my own head, father, daydreamer, idealist and member of Tech Digital Magazine Linkeado
Updated on February 03, 2020Comments
-
PedroC88 about 4 years
If I add jobs to the thread pool with
QueueUserWorkItem
... how do I keep my program from going forward until all jobs are completed?I know I could add some logic to keep the app from running until all jobs are completed, but I want to know if there is something like
Thread.Join()
or if there's any way to retrieve each thread that is being assigned a job.-
Chris Shain over 12 yearsWhich version of .NET are you using?
-
-
PedroC88 almost 13 yearsThis would easily work for queuing one job at a time... but If I had multiple jobs then I would need a buckle to control it? Wouldn't I? If not... How is that adaptable to multiple queued jobs?
-
Bas Smit about 10 yearsthis has a limit of 64 items. As the other answers show there are more suitable constructs for dealing with multiple tasks, but if you are targeting older profiles you can use a single event and use a counter decremented with Interlocked.Decrement
-
newprint over 9 yearsIt is great solution, unfortunately it only works in .NET 4 and up.
-
John Odom almost 9 years@BrianGideon Excellent answer! But how would I be able to cancel the threads prematurely with
CountdownEvent
? Like if I was using this in a Windows Forms application and the user closes the form but there are threads running. -
Brian Gideon almost 9 years@JohnOdom: This answer is a bit outdated. A more contemporary solution is to use the Task Parallel Library for stuff like this. Anyway, included in the TPL is the cooperative cancellation classes. That's what should be used to gracefully terminate threads.
-
Mike about 8 yearsDrewR, could you provide an example that answers the question?
-
Drew R about 8 yearsI added an example - note this is a .NET 4 feature
-
Dima over 4 years@BrianGideon what would you recommend from TPL for this case?
-
Jay Brown about 3 yearsThe UI thread freezes when I use the resetEvent.WaitOne() method. How can I avoid that?