如何让前台线程等待所有后台(子)线程在C#中完成?我需要从队列(数据库)获取待处理作业的列表,启动一个新线程来执行每个作业,最后等待所有子线程完成。如何在C#中做到这一点?提前谢谢。
答案 0 :(得分:7)
您可以将每个已启动的线程存储在一个数组中。然后当你需要等待它们时,在循环中的数组中的每个线程上调用Join方法。
Thread child = new Thread(...);
Threads.Add(child);
child.Start()
...
foreach(Thread t in Threads)
{
t.Join();
}
HTH
答案 1 :(得分:1)
这是不完整的代码,但ManualResetEvent
适合您
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());
答案 2 :(得分:1)
考虑使用ThreadPool。您想要的大部分内容已经完成。有一个example from Microsoft可以完成你的整个任务。将“fibonacci”替换为“数据库任务”,这听起来像是你的问题。
答案 3 :(得分:1)
使用动态数据,您可以传递对象和WaitHandle(ActionResetEvent),它可以让您等待所有后台线程完成而无需声明额外的类:
static void Main(string[] args)
{
List<AutoResetEvent> areList = new List<AutoResetEvent>();
foreach (MyObject o in ListOfMyObjects)
{
AutoResetEvent are = new AutoResetEvent(false);
areList.Add(are);
ThreadPool.QueueUserWorkItem(DoWork, new { o, are });
};
Console.WriteLine("Time: {0}", DateTime.Now);
WaitHandle.WaitAll(areList.ToArray());
Console.WriteLine("Time: {0}", DateTime.Now);
Console.ReadKey();
}
static void DoWork(object state)
{
dynamic o = state;
MyObject myObject = (MyObject)o.o;
AutoResetEvent are = (AutoResetEvent)o.are;
myObject.Execute();
are.Set();
}
答案 4 :(得分:0)
创建一个跟踪工作线程的结构
private struct WorkerThreadElement
{
public IAsyncResult WorkerThreadResult;
public AsyncActionExecution WorkerThread;
}
您还需要跟踪预期要创建的线程总数以及当前已完成的线程数
private int _TotalThreads = 0;
private int _ThreadsHandled = 0;
private List<WorkerThreadElement> _WorkerThreadElements = new List<WorkerThreadElement>();
然后创建一个自动复位句柄以等待线程完成。
// The wait handle thread construct to signal the completion of this process
private EventWaitHandle _CompletedHandle = new AutoResetEvent(false);
您还需要一个委托来创建新线程 - 有多种方法可以做到这一点,但为了这个例子,我选择了一个简单的委托
// Delegate to asynchronously invoke an action
private delegate void AsyncActionExecution();
让我们假设Invoke方法是创建所有线程并等待它们执行的入口点。所以我们有:
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是用于为一个操作创建单个线程的方法。这里我们需要创建一个工作线程元素并调用实际的线程。
private void InvokeOneThread()
{
WorkerThreadElement threadElement = new WorkerThreadElement();
threadElement.WorkerThread = new AsyncActionExecution();
threadElement.WorkerThreadResult = threadElement.WorkerThread.BeginInvoke(actionParameters, InvokationCompleted, null);
_WorkerThreadElements.Add(threadElement);
}
从线程完成回调
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();
}
完成