【问题标题】:BackgroundWorker - CancellationPending changing to false in RunWorkerCompleted. Why?BackgroundWorker - Cancellation Pending 在 RunWorkerCompleted 中更改为 false。为什么?
【发布时间】:2012-07-29 23:59:55
【问题描述】:

取消BackGroundWorker后,在DoWork中,CancellationPending为true,但当他来到RunWorkerCompleted时,CancellationPending为false。我不知道我做错了什么?

static BackgroundWorker b1;

static void Main(string[] args)
{
    b1=new BackgroundWorker();
    b1.DoWork += new DoWorkEventHandler(work1);
    b1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(completed);
    b1.WorkerSupportsCancellation = true;
    b1.RunWorkerAsync("Hellow");
    Console.ReadLine();
}

private static void completed(object sender, RunWorkerCompletedEventArgs e)
{
    if (((BackgroundWorker)sender).CancellationPending)
        Console.WriteLine("Canceled!");
    else
        Console.WriteLine("Result:" + e.Result);//it goes here every time
}

private static void work1(object sender, DoWorkEventArgs e)
{
    ((BackgroundWorker)sender).CancelAsync();
    if (((BackgroundWorker)sender).CancellationPending)
    {
        e.Cancel = true;
    }
}

顺便说一句,如何将 DoWork 中发生的错误添加到 RunWorkerCompletedEventArgs.Error 以将其告知用户?

【问题讨论】:

    标签: c# backgroundworker


    【解决方案1】:

    是的,BackgroundWorker 类在引发 RunWorkerCompleted 事件之前将 CancellationPending 属性设置为 false。工人是否真的被取消了。

    这是有意为之的,它可以防止您掉入使用线程时始终存在的令人讨厌的陷阱。由于一种称为“线程竞争”的错误,使用线程的代码通常会随机且不可预测地行为异常。这是一种非常常见的错误,调试起来非常困难。

    如果 BGW 不这样做,那么在您的预期方法中很容易出错的是,当您看到 CancellationPending 设置为 true 时,您会假设工作人员已被取消。但这是一种错觉,你无法分辨它被取消和正常完成之间的区别。极端情况是您在工作人员完成前一微秒调用 CancelAsync()。工作人员甚至没有机会看到 CancellationPending 标志设置为 true,它正忙于完成 DoWork 事件处理程序方法的最后一位。那是线程竞赛,工作人员在您的调用之前就竞赛并正常完成。

    避免此错误的正确握手是您的工作人员在看到 CancellationPending 属性设置为 true 时将 e.Cancel 设置为 true。当然,停止它正在做的事情。现在可以确定了,RunWorkerCompleted 事件处理程序中的 e.Cancelled 属性是 e.Cancel 的副本。因此,您的代码现在可以可靠地告诉您工作人员是否看到了取消请求。

    【讨论】:

    • 如果您传递 BackgroundWorker 对象,您还必须传递 DoWorkEventArgs 以执行 Hans 的建议。我通常调用 BackgroundWorker worker 和 DoWorkEventArgs dwea - 然后我可能有我做的上下文:if(worker.CancellationPending){dwea.Cancel = true; return;}
    【解决方案2】:

    我相信 CancellationPending 属性是在后台操作期间使用的(在您的 work1 方法中)。它将告诉后台工作人员您已请求取消后台操作。一旦调用了 RunWorkerCompleted 事件,后台工作人员已经完成了取消请求的工作,因此取消不再处于挂起状态。

    编辑:RunWorkerCompletedEventArgs 有一个 Canceled 属性,它会告诉你后台操作是否被取消。

    如果您从 DoWork 方法(在您的情况下为 work1)抛出异常,它应该被 BackgroundWorker 捕获并填充 RunWorkerCompletedEventArgs 的 Error 属性。

    【讨论】:

    • 在每个在线示例中,他们使用 RunWorkerCompleted 中的 CancellationPending 来检查 bgw 是否被取消。感谢您的宝贵时间,但您不正确。
    • 其实@brian s 是正确的。您需要检查已完成函数中 RunWorkerCompletedEventArgs 参数中的 Canceled 标志。 msdn.microsoft.com/en-us/library/…
    • 是的,谢谢@Surfbutler,我忘了取消标志。
    • 喂!我明白了,谢谢你们,我很抱歉 Brain S。再次感谢你们。
    • 不用担心,如果我记得 Canceled 标志,它就不会那么混乱了。很高兴你解决了。我将编辑答案,以免将来混淆其他人。
    猜你喜欢
    • 2020-01-19
    • 2011-02-17
    • 1970-01-01
    • 1970-01-01
    • 2013-08-17
    • 1970-01-01
    • 2019-03-19
    • 1970-01-01
    相关资源
    最近更新 更多