2010-10-13 121 views
5

如何让前台线程等待所有后台(子)线程在C#中完成?我需要从队列(数据库)中获取待处理作业的列表,启动一个新线程来执行它们中的每一个,并最终等待所有子线程完成。如何在C#中做到这一点?提前致谢。如何等待所有后台线程完成(在C#中)?

+2

可能重复的工作然后等到所有完成](http://stackoverflow.com/questions/2528907/c-spawn-multiple-threads-for-work-then-wait-until-all-finished) – 2010-10-13 13:25:33

+0

感谢所有的快速答复我的问题 – RKP 2010-10-13 15:14:13

+0

你尝试[EventWaitHandle();](http://msdn.microsoft.com/en-us/library/system.threading.eventwaithandle.aspx) – Bonshington 2010-10-13 13:47:13

回答

1

考虑使用线程池。你想要的大部分已经完成了。有一个example from Microsoft它几乎完成你的整个任务。将“fibonacci”替换为“数据库任务”,听起来像是你的问题。

+0

我几分钟前就读过这篇文章,并即将回复说这是我正在寻找的解决方案。谢谢回复。 – RKP 2010-10-13 15:06:50

7

您可以将每个启动的线程存储在一个数组中。然后当你需要等待它们全部时,在循环中的数组中的每个线程上调用Join方法。

Thread child = new Thread(...); 
Threads.Add(child); 
child.Start() 

... 

foreach(Thread t in Threads) 
{ 
    t.Join(); 
} 

HTH

+0

感谢您的答复。我认为thread.Join方法适用于单线程或非常少的固定线程数。对于多线程,我认为有一个WaitAll方法,但我找不到一个好的代码示例。 – RKP 2010-10-13 13:37:54

+3

@RKP:等待所有线程完成和等待它们一样,不是吗?有一个winapi函数WaitForMultipleObjects,但它不是C#,尽管你可以使用它,但我没有看到任何意义。 – 2010-10-13 13:40:25

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()); 
+0

谢谢,但是每个动作的新线程是从这里开始的呢?是“5000”超时设置? – RKP 2010-10-13 13:42:31

+0

在这里寻找完整的代码,我只是从我之前的答案中复制了一下:http://stackoverflow.com/questions/3915017/image-url-validation-in-c/3915440#3915440 – danijels 2010-10-13 13:49:47

+0

是的,5000是超时设置 – danijels 2010-10-13 13:50:02

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(); 

让asume的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(); 
} 

完成

1

使用动态数据,你可以通过你的对象和WaitHandle的(ActionResetEvent),让你等待所有的后台线程完成不宣而一个额外的类:[C#产生多个线程的

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(); 
}