[英]how to handle this race condition?
在我的课堂上,我使用BackgroundWorker。 在某个时候,我需要取消可能正在进行的异步操作,并立即启动另一个操作。 代码如下。 我不确定的一件事是,如果工人在我将lambda分配给RunWorkerCompleted事件之前立即完成,则可能会发生竞争状况。 如果发生这种情况,我的lambda将永远不会被调用。 代码中的注释显示了这个地方。 关于如何处理这个有什么意见吗?
谢谢康斯坦丁
if (this.worker.IsBusy)
{
RunWorkerCompletedEventHandler f = null;
f = (s, v) =>
{
this.RunWorkerCompleted -= f;
this.worker.RunWorkerAsync();
};
// what if worker completes right before the following statement?
this.worker.RunWorkerCompleted += f;
this.worker.CancelAsync();
}
else
{
this.worker.RunWorkerAsync();
}
只要此代码在主线程上运行,就不会发生竞争。 仅当RunWorkerCompleted事件处理程序完成运行时,BGW才能完成。 在主线程重新进入消息循环之前,该处理程序无法开始运行。
然而,由else子句引起的另一种竞赛。 您让BGW在没有 RunWorkerCompleted事件处理程序的情况下启动。 现在它可以异步完成,因为它不会被阻塞。 始终订阅该事件,测试e。已取消以了解发生了什么。
您可以只在ctor中添加一次RunWorkerCompleted事件处理程序,还可以向该类中添加一个布尔成员变量“ restart”。 然后,您可以编写if(IsBusy)restart = true,然后在处理程序中检查if(restart)Run()。 您可以将重新启动定义为易失性,以避免在这种情况下出现争用情况。
我认为在您的案例中添加和删除事件处理程序不是一个好习惯。
也许我不够聪明,无法理解您的代码。 但是在我的世界中,我会建立一个Queue<Action>
并填写所有必须完成的工作。
另一个线程(或BackgroundWorker)将查看此Queue并按顺序处理队列中的所有作业(例如我在此处的回答 )。 由于在循环中使用Thread.Sleep(1)
的拉模式,这可能不是很优雅。
但这可以通过创建从Queue<T>
派生并实现IBindingList
的BindingQueue<T>
来实现。 因此,您可以等待此类事件,出队并调用Action
直到队列为空,然后重新开始。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.