取消标志在停止和重新启动 BGWorker 时是否会受到竞争条件的影响

本文关键字:竞争 条件 影响 是否 标志 BGWorker 重新启动 取消 | 更新日期: 2023-09-27 18:35:44

我看到了这个答案

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

以及 CancelAsync 和 RunWorkerAsync 的文档

我有这段代码可以防止抛出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,但我没有找到确认。

取消标志在停止和重新启动 BGWorker 时是否会受到竞争条件的影响

根据这个是正确的:背景工作者.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);
    }

是的,有非常强大的种族潜力。 RunWorkerComplete事件处理程序可能需要一段时间才能开始运行,这取决于UI线程正在执行的操作。 它可能已经完成很长时间,并且您无法从UI线程中发现它是完成的。 BGW 重置取消挂起的原因,它没有告诉您任何关于真正发生的事情。

您必须仔细编码,以便检测到它实际上已被取消。 大约:

    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 很重要,这就是在 RunWorkerDone 事件处理程序中设置 e.Cancel

(已取消)的内容