停止并重新启动BGWorker时,取消标志是否会出现竞争状况?

时间:2014-12-30 14:51:17

标签: c# backgroundworker race-condition

我已经看到了answer

  

是的,BackgroundWorker类在引发RunWorkerCompleted事件之前将CancellationPending属性设置为false。

以及CancelAsyncRunWorkerAsync

的文档

我有这段代码可以防止InvalidOperationException被抛出。这是我的代码,所以WorkerSupportsCancellation是真的。

public void Start()
{
    lock (OnOffLock)
    {
        if (worker.IsBusy)
            return;
        worker.RunWorkerAsync();
    }
}
public void Stop()
{
    lock (OnOffLock)
    {
        worker.CancelAsync();
    }
}

我知道如果我在工作人员已经停止(无论出于何种原因)时呼叫CancelAsync,就无法避免发生可能的竞争条件。我想知道的是它可能是常识,但在文档中没有解释。

调用RunWorkerAsync时(例如,在停止后重新启动工作人员),将CancellationPending设置为false以避免未处理的取消?

我的猜测是,在调用RunWorkerAsync时,CancellationPending标志设置为false,无论其先前的值是多少,但我没有找到确认。

2 个答案:

答案 0 :(得分:1)

根据这是正确的:BackgroundWorker.cs

public void RunWorkerAsync(object argument)
    {
        if (isRunning)
        {
            throw new InvalidOperationException(SR.GetString(SR.BackgroundWorker_WorkerAlreadyRunning));
        }

        isRunning = true;
        cancellationPending = false;

        asyncOperation = AsyncOperationManager.CreateOperation(null);
        threadStart.BeginInvoke(argument,
                                null,
                                null);
    }

答案 1 :(得分:1)

是的,非常强大的竞争潜力。您的RunWorkerCompleted事件处理程序可能需要一段时间才能开始运行,这取决于您的UI线程正在执行的操作。它可能需要很长时间才能完成,并且您无法从UI线程中找到它。 BGW重置CancellationPending的原因是,它没有告诉你任何关于真实情况的信息。

您必须仔细编码,以便检测到实际被取消。大致是:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
        (some-loop-construct) {
            if (backgroundWorker1.CancellationPending) {
               e.Cancel = true;    // Important!
               return;
            }
            // etc...
        }
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        if (e.Error != null) {
            // Something bad happened
        }
        else if (e.Cancelled) {
            // It actually got cancelled
        }
        else {
            // It actually completed
        }
    }

在DoWork事件处理程序中将e.Cancel设置为true非常重要,这就是在RunWorkerCompleted事件处理程序中设置e.Cancelled的原因