【问题标题】:Waiting for either of these BackgroundWorker to complete等待这些 BackgroundWorker 中的任何一个完成
【发布时间】:2010-02-02 01:39:38
【问题描述】:
应该使用服务下载 FORM(某些 UI)的序列。
目前,此下载位于 BackgroundWorker 线程中。
现在,由于性能很慢......我们决定将 FORMS 分为 2 类,并开始使用现有线程之上的另一个 BackgroundWorker 并行下载。
现在,场景是这个 BackgroundWorker 应该等待另一个完成。
那么,如何实现呢。
我尝试使用 AutoResetEvent。但是,我无法做到这一点。
感谢任何帮助。
【问题讨论】:
标签:
c#
.net
multithreading
backgroundworker
【解决方案1】:
我不认为这种情况真的是一个BackgroundWorker 应该等待另一个。您真正想要的是在它们都完成之后(并且仅在之后)触发一些 UI 事件。这是一个微妙但重要的区别。第二个版本更容易编码。
public class Form1 : Form
{
private object download1Result;
private object download2Result;
private void BeginDownload()
{
// Next two lines are only necessary if this is called multiple times
download1Result = null;
download2Result = null;
bwDownload1.RunWorkerAsync();
bwDownload2.RunWorkerAsync();
}
private void bwDownload1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
download1Result = e.Result;
if (download2Result != null)
DisplayResults();
}
private void bwDownload2_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
download2Result = e.Result;
if (download1Result != null)
DisplayResults();
}
private void DisplayResults()
{
// Do something with download1Result and download2Result
}
}
注意那些object 引用应该是强类型的,我只是使用object 因为我不知道你在下载什么。
这真的是你所需要的; RunWorkerCompleted 事件在前台线程中运行,因此您实际上不必担心那里的同步或竞争条件。不需要lock 语句、AutoResetEvent 等。只需使用两个成员变量来保存结果,或者如果两者的结果实际上可以是null,则使用两个布尔标志。
【解决方案3】:
Jeffrey Richter 是多线程方面的大师,他编写了一个名为 Power Threading Library 的出色库,它可以执行诸如异步下载 n 个文件并在它们全部完成(或一个或一些)后继续执行等任务,非常简单。
花点时间观看视频,了解它,您不会后悔的。使用强大的线程库(免费并且还具有 Silverlight 和 Compact Framework 版本)还可以使您的代码更易于阅读,这在执行任何异步操作时是一个很大的优势。
祝你好运,
标记
【解决方案4】:
int completedCount = 0;
void threadProc1() { //your thread1 proc
//do something
....
completedCount++;
while (completedCount < 2) Thread.Sleep(10);
//now both threads are done
}
void threadProc2() { //your thread1 proc
//do something
....
completedCount++;
while (completedCount < 2) Thread.Sleep(10);
//now both threads are done
}
【解决方案5】:
只需使用 2 个 BackgroundWorker 对象,并让每个对象在完成时向 UI 发出警报。这样,您可以在 UI 上显示微调器、进度条等任何内容,并在下载结果从线程返回时对其进行更新。您还将避免任何线程死锁等风险。
顺便说一下,我们都清楚,你不应该从 UI 线程调用诸如 WaitAll 之类的阻塞函数。它会导致 UI 完全锁定,这会让你的用户怀疑 WTF 正在发生:)