现在我正在产生3个线程来做一些并发工作,我使用Threadpooling进行设置,因为我希望所有线程同时运行,但是在继续之前让所有线程完成。以下是代码的要点:
_resetEvents = new ManualResetEvent[3];
_resetEvents[0] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(DoWorkA);
_resetEvents[1] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(DoWorkB);
_resetEvents[2] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(DoWorkC);
WaitHandle.WaitAll(_resetEvents);
但我的方法都使用相同的代码库,我把它分解为3种方法只是为了设置()正确的线程。
private void DoWorkA(object o) {
var workerClass = new WorkerClass();
workerClass.Process();
_resetEvents[0].Set();
}
private void DoWorkB(object o) {
var workerClass = new WorkerClass();
workerClass.Process();
_resetEvents[1].Set();
}
private void DoWorkC(object o) {
var workerClass = new WorkerClass();
workerClass.Process();
_resetEvents[2].Set();
}
显然它不是很干,因为我想拥有4个或5个线程,但是想要确保Set()在完成后设置正确的_resetEvent。
关于如何安全地做到这一点并使其更干燥和可扩展的任何建议?
答案 0 :(得分:5)
您可以使用TPL中的任务而不是线程,并且不需要等待句柄:
Action execute = () => {
var worker = new WorkerClass();
worker.Process();
};
var task1 = Task.Run(execute);
var task2 = Task.Run(execute);
var task3 = Task.Run(execute);
Task.WaitAll(task1, task2, task3);
或者,或者:
Action execute = () => (new WorkerClass()).Process();
Parallel.Invoke(execute, execute, execute);
如果您需要将此缩放为N个项目,可以切换到PLINQ或Parallel.For / ForEach,并使用:
int numToRun = 42;
ParallelEnumerable.Range(0, numToRun).ForAll(i => (new WorkerClass()).Process());
答案 1 :(得分:1)
使用框架4+:
Parallel.Invoke(
() => DoworkA(),
() => DoworkB(),
() => DoworkC()
);
包括等待和异常转发。
答案 2 :(得分:1)
像Parallel.ForEach这样的东西可能更好。
否则只是将传入参数视为数组中的索引可能就足够了:
private void DoWork(object index)
{
var workerClass = new WorkerClass();
workerClass.Process();
_resetEvents[(int)index].Set();
}
ThreadPool.QueueUserWorkItem(DoWork, 0);