让我们先解决一些问题。
- 不要为此创建单独的线程。线程是一种昂贵的资源。而是使用线程池技术。
- 不要通过调用 , 或任何其他阻塞机制来阻塞 UI
Thread.Join
线程WaitHandle.WaitOne
。
以下是我将如何使用 TPL 执行此操作。
private void repairClientsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (machineList.Count() != 0)
{
// Start the parent task.
var task = Task.Factory.StartNew(
() =>
{
foreach (string ws in machineList)
{
string capture = ws;
// Start a new child task and attach it to the parent.
Task.Factory.StartNew(
() =>
{
fixClient(capture);
}, TaskCreationOptions.AttachedToParent);
}
}, TaskCreationOptions.LongRunning);
// Define a continuation that happens after everything is done.
task.ContinueWith(
(parent) =>
{
// Code here will execute after the parent task including its children have finished.
// You can safely update UI controls here.
}, TaskScheduler.FromCurrentSynchronizationContext);
}
else
{
MessageBox.Show("Please import data before attempting this procedure");
}
}
我在这里所做的是创建一个父任务,它本身会启动子任务。请注意,我使用TaskCreationOptions.AttachedToParent
将子任务与其父任务相关联。然后在我调用的父任务上,该任务在父任务ContinueWith
及其所有子任务完成后执行。我TaskScheduler.FromCurrentSynchronizationContext
用来让 UI 线程上的继续发生。
这是使用Parallel.ForEach
. 请注意,这是一个更清洁的解决方案。
private void repairClientsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (machineList.Count() != 0)
{
// Start the parent task.
var task = Task.Factory.StartNew(
() =>
{
Parallel.Foreach(machineList,
ws =>
{
fixClient(ws);
});
}, TaskCreationOptions.LongRunning);
// Define a continuation that happens after everything is done.
task.ContinueWith(
(parent) =>
{
// Code here will execute after the parent task has finished.
// You can safely update UI controls here.
}, TaskScheduler.FromCurrentSynchronizationContext);
}
else
{
MessageBox.Show("Please import data before attempting this procedure");
}
}