RunWorkerAsync完成后关闭BackgroundWorker

时间:2012-05-17 10:34:34

标签: c# .net multithreading asynchronous backgroundworker

我有一个后台工作程序,需要根据选中的复选框的数量多次调用 - 我已经写了这个来获取复选框值并将它们放入List

List repSelected = new List();

这是填充的,然后迭代迭代:

foreach (string rep in repSelected)
{
    backgroundWorker1.RunWorkerAsync(rep);
    backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
}

异步,DoWork代码如下所示:

BackgroundWorker worker = sender as BackgroundWorker;
string rep = e.Argument.ToString();

if (worker.CancellationPending == true)
{
    e.Cancel = true;
}
else
{
    DirectoryExists(rep);
    ProcessRunner(rep); //Rars some large files - expensive
}

然后该进程运行WorkerComplete,问题是当进程返回到Worker的下一次迭代时它会崩溃说工作者正忙 - 即使工作者已经返回它的WorkerCompleted状态。

如何在循环的下一次迭代之前确保线程已关闭?

注意:我对包含!backgroundWorker1.IsBusy()的后台工作者有条件,但这(显然)只是在没有执行的情况下跳过剩余的迭代。

5 个答案:

答案 0 :(得分:1)

如果要按顺序处理每个项目,则没有理由为每个任务使用单独的后台工作程序。因此,将foreach循环移动到DoWork方法会更好。但是如果你想在并行处理所有项目,你需要为每个项目创建一个后台工作者。

答案 1 :(得分:1)

来自MSDN:

  

如果后台操作已在运行,则再次调用RunWorkerAsync将引发InvalidOperationException。

因此,您无法使用BackgroundWorker来维护队列任务(并且您可以按顺序推送所有任务,而无需等待之前的任务完成)。您有不同的解决方案,例如,如果您想继续使用BackgroundWorker,您可以这样做:

backgroundWorker1.RunWorkerAsync(repSelected);

然后更改您的DoWork方法,如下所示:

BackgroundWorker worker = sender as BackgroundWorker;

foreach (string rep in (IEnumerable<string>)e.Argument)
{
    if (worker.CancellationPending == true)
    {
        e.Cancel = true;
        return;
    }
    else
    {
        DirectoryExists(rep);
        ProcessRunner(rep); //Rars some large files - expensive
    }
}

作为替代方案,您可以考虑更改执行此任务的方式,例如使用System.Threading.Tasks.TaskThreadPool(直接或间接,大多数并行操作将排队到池中)。

答案 2 :(得分:1)

您的foreach-code将立即触发所有元素的工作。这就是你得到例外的原因。

如果要按顺序启动工作程序,则只能在启动时调用RunWorkerAsync,然后为每个WorkerComplete事件调用。但是为什么不在工作代码中进行处理?

答案 3 :(得分:1)

BackgroundWorker真的很忙,因为第一次调用backgroundWorker1.RunWorkerAsync(rep);时,它不等待任何事情,然后立即调用第二个,第三个......调用。

你应该在每次调用时创建BackgroundWorker,然后就可以了。

答案 4 :(得分:1)

您可以使用parallel.foreach和多个backgroundworkers;

Parallel.ForEach(YourListofStrings,
                 (q) =>
                 {
                     BackgroundWorker worker = new BackgroundWorker();
                     worker.DoWork += new DoWorkEventHandler(worker_DoWork);
                     worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
                     worker.RunWorkerAsync(q);
                 });