繁体   English   中英

如何处理这种比赛情况?

[英]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>派生并实现IBindingListBindingQueue<T>来实现。 因此,您可以等待此类事件,出队并调用Action直到队列为空,然后重新开始。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM