Hi, how to make the foreground thread wait for all background (child) threads to finish in C#? I need to get list of pending jobs from the queue (database), start a new thread to execute each of them and finally wait for all the child threads to finish. how to do that in C#? Thanks in advance.
Look into the Thread.Join()
method. The calling thread will be paused while it waits for the thread passed in as a parameter.
If you keep a reference to all the threads that you create with new Thread()
then after you have looped through them all and started them, loop through again and call Join()
on each.
This is a very simplistic and possibly crude way to solve the problem though. Blocking the main thread might cause bad (user?) experience if related to a user-interface or even make your program unresponsive. If you add more context to the question, you might get better tailored answers. Possibly you need a callback mechanism from the background threads so that you know when they've each finished.
You could store each launched thread in an array. Then when you need to wait for them all, call Join method on each thread in an array in a loop.
Thread child = new Thread(...);
Threads.Add(child);
child.Start()
...
foreach(Thread t in Threads)
{
t.Join();
}
HTH
This is incomplete code, but ManualResetEvent
works for you
var waitEvents = new List<ManualResetEvent>();
foreach (var action in actions)
{
var evt = new ManualResetEvent(false);
waitEvents.Add(evt);
ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, TimeoutCallback, state, 5000, true);
}
if (waitEvents.Count > 0)
WaitHandle.WaitAll(waitEvents.ToArray());
Create a structure to keep track of your worker threads
private struct WorkerThreadElement
{
public IAsyncResult WorkerThreadResult;
public AsyncActionExecution WorkerThread;
}
You also need to keep track the total number of threads expected to be created and the number of threads that have currently completed
private int _TotalThreads = 0;
private int _ThreadsHandled = 0;
private List<WorkerThreadElement> _WorkerThreadElements = new List<WorkerThreadElement>();
Then create an autoreset handle in order to wait for thread completion.
// The wait handle thread construct to signal the completion of this process
private EventWaitHandle _CompletedHandle = new AutoResetEvent(false);
You also need a delegate to create new threads - There are multiple ways of doing this but i have chosen a simple delegate for the sake of this example
// Delegate to asynchronously invoke an action
private delegate void AsyncActionExecution();
Lets asume that the Invoke method is the entrance point that will create all threads and wait for their execution. So we have:
public void Invoke()
{
_TotalThreads = N; /* Change with the total number of threads expected */
foreach (Object o in objects)
{
this.InvokeOneThread();
}
// Wait until execution has been completed
_CompletedHandle.WaitOne();
// Collect any exceptions thrown and bubble them up
foreach (WorkerThreadElement workerThreadElement in _WorkerThreadElements)
{ workerThreadElement.WorkerThread.EndInvoke(workerThreadElement.WorkerThreadResult);
}
}
InvokeOneThread is the method used to create a single thread for one operation. Here we need to create a worker thread element and invoke the actual thread.
private void InvokeOneThread()
{
WorkerThreadElement threadElement = new WorkerThreadElement();
threadElement.WorkerThread = new AsyncActionExecution();
threadElement.WorkerThreadResult = threadElement.WorkerThread.BeginInvoke(actionParameters, InvokationCompleted, null);
_WorkerThreadElements.Add(threadElement);
}
Callback from thread completion
private object _RowLocker = new object();
/// <summary>
/// Increment the number of rows that have been fully processed
/// </summary>
/// <param name="ar"></param>
private void InvokationCompleted(IAsyncResult ar)
{
lock (_RowLocker) { _RowsHandled++; }
if (_TotalThreads == _ThreadsHandled) _CompletedHandle.Set();
}
Done
Consider using ThreadPool. Most of what you want is already done. There is an example from Microsoft which does pretty much your entire task. Replace "fibonacci" with "database task" and it sounds like your problem.