mar*_*ark 37 .net multithreading backgroundworker
请注意以下代码:
var handler = GetTheRightHandler();
var bw = new BackgroundWorker();
bw.RunWorkerCompleted += OnAsyncOperationCompleted;
bw.DoWork += OnDoWorkLoadChildren;
bw.RunWorkerAsync(handler);
Run Code Online (Sandbox Code Playgroud)
现在假设我想等到bw完成工作.这样做的正确方法是什么?
我的解决方案是:
bool finished = false;
var handler = GetTheRightHandler();
var bw = new BackgroundWorker();
bw.RunWorkerCompleted += (sender, args) =>
{
OnAsyncOperationCompleted(sender, args);
finished = true;
});
bw.DoWork += OnDoWorkLoadChildren;
bw.RunWorkerAsync(handler);
int timeout = N;
while (!finished && timeout > 0)
{
Thread.Sleep(1000);
--timeout;
}
if (!finished)
{
throw new TimedoutException("bla bla bla");
}
Run Code Online (Sandbox Code Playgroud)
但我不喜欢它.
我已经考虑用finished同步事件替换标志,在RunWorkerCompleted处理程序中设置它并在以后阻塞它而不是执行while-sleep循环.
唉,这是错误的,因为代码可能在WPF或WindowsForm同步上下文中运行,在这种情况下,我会阻止与RunWorkerCompleted处理程序运行相同的线程,这显然不是非常聪明的举动.
我想知道一个更好的解决方案.
谢谢.
编辑:
PS
Thread.Join,Delegate.BeginInvoke,ThreadPool.QueueUserWorkItem,等...问题是,特别是约BackgroundWorker.编辑2:
好吧,我想如果我解释这个场景会更容易.
我有一个单元测试方法,它调用一些异步代码,这反过来最终会使BackgroundWorker我能够传递一个完成处理程序.所有的代码都是我的,所以如果我愿意,我可以改变实现.但是,我不会更换BackgroundWorker,因为它会自动使用正确的同步上下文,因此当在UI线程上调用代码时,在同一UI线程上调用完成回调,这非常好.
无论如何,单元测试方法有可能在BW完成其工作之前结束,这是不好的.所以我希望等到BW完成并想知道它的最佳方法.
它有更多的部分,但整体情况或多或少像我刚才描述的那样.
Joh*_*esH 44
尝试使用AutoResetEvent类,如下所示:
var doneEvent = new AutoResetEvent(false);
var bw = new BackgroundWorker();
bw.DoWork += (sender, e) =>
{
try
{
if (!e.Cancel)
{
// Do work
}
}
finally
{
doneEvent.Set();
}
};
bw.RunWorkerAsync();
doneEvent.WaitOne();
Run Code Online (Sandbox Code Playgroud)
注意:doneEvent.Set()无论发生什么情况,都应该确保调用它.此外,您可能希望提供doneEvent.WaitOne()指定超时期限的参数.
注意:此代码几乎是Fredrik Kalseth对类似问题的回答.
Azh*_*any 19
要等待后台工作线程(单个或多个),请执行以下操作:
创建以编程方式创建的后台工作程序列表:
private IList<BackgroundWorker> m_WorkersWithData = new List<BackgroundWorker>();
Run Code Online (Sandbox Code Playgroud)在列表中添加后台worker:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.WorkerReportsProgress = true;
m_WorkersWithData.Add(worker);
worker.RunWorkerAsync();
Run Code Online (Sandbox Code Playgroud)使用以下函数等待List中的所有worker:
private void CheckAllThreadsHaveFinishedWorking()
{
bool hasAllThreadsFinished = false;
while (!hasAllThreadsFinished)
{
hasAllThreadsFinished = (from worker in m_WorkersWithData
where worker.IsBusy
select worker).ToList().Count == 0;
Application.DoEvents(); //This call is very important if you want to have a progress bar and want to update it
//from the Progress event of the background worker.
Thread.Sleep(1000); //This call waits if the loop continues making sure that the CPU time gets freed before
//re-checking.
}
m_WorkersWithData.Clear(); //After the loop exits clear the list of all background workers to release memory.
//On the contrary you can also dispose your background workers.
}
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
76037 次 |
| 最近记录: |