【问题标题】:Backgroundworker : exception during cancellation后台工作者:取消期间的异常
【发布时间】:2010-11-06 02:58:08
【问题描述】:

我有一个可以取消的后台工作人员。

当 CancelPending 变量变为 true 时(响应 UI 上调用 worker.CancelAsynch() 的用户交互),正常流程会自行中断,抛出异常,因为如果那样(因为正常流程被中断,很多 null ref 异常抛出)

所以当worker返回时,我希望能够区分worker时已经抛出的异常 当工作人员未取消时(将它们报告给 UI)时抛出的异常被取消(以静默忽略它们)。

我的代码如下(对不起 c#/vb 混合...):

工人阶级:

Public Class ClassBaseGetObjectsWorker
    Inherits System.ComponentModel.BackgroundWorker
    

 Protected Overrides Sub OnDoWork(ByVal e As System.ComponentModel.DoWorkEventArgs)
        Try

            Dim cpt As Int16 = 0
            While cpt < 5
                System.Threading.Thread.Sleep(1000)
                cpt = cpt + 1
                If CheckForCancellation() Then
                    'Simulating exception due to cancel
                    Throw New Exception("Exception du to cancel !")
                End If
            End While

        Catch exc As Exception
            e.Cancel = Me.CancellationPending
            Throw exc
        End Try

    End Sub
End Class

回调:

void setObjSetCollWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
    if (e.Cancelled) {
        resultLabel.Text += "Canceled";
        //e.Error is selently ignored
    }
    else {
        if (e.Error != null) {
            //Reporting errors arising during normal (uncanceled) flow
            throw e.Error.InnerException;
        }
        else {
            //Worker process finished without error or being canceled.
            updateUIAfterBackgroundJob();
        }
    }
}

然后,当我在执行 worker.CancelAsynch() 时,e.Cancelled 在 Completed 回调中设置为 false(这不是我所期望的)。如果我在工作人员中注释掉“Trow exc”,如果我再次测试,则 e.Cancelled 正确设置为 true。

获取我想要的信息的最干净的方法是:我想知道当worker处于cancellationPending状态时是否抛出了在完成处理程序中弹出的异常?

【问题讨论】:

  • 工作代码是什么样子的,它是如何处理被取消的?
  • worker 类似于上面的模拟代码:它经过几个级别的函数调用,如果 CancellationPending(通过委托检查)变为 true,则每个循环都将退出。考虑到流被中断并且结果将被丢弃的事实,那些循环和函数过早退出会导致“正常”异常。为什么要问这个?

标签: c# multithreading exception backgroundworker


【解决方案1】:

如果在 OnDoWork() 实现中构建代码的最佳方式是在检测到取消时抛出异常,请执行以下操作:

创建一个 CancelException:

public class CancelException: Exception {}

当您检测到取消挂起时抛出此 CancelException:

if(CheckForCancellation()) throw new CancelException();

在您的 OnDoWork() 方法中的代码周围添加一个 try-catch:

protected override void OnDoWork(DoWorkEventArgs e){
  try{
    //...
  }
  catch(CancelException){
    // silently return
    return;
  }
}

这样您的代码将遵守 BackgroundWorker 合同(当您检测到取消挂起时从 OnDoWork() 返回,而不是抛出异常),并且 Canceled 属性现在应该与您预期的一样

【讨论】:

  • 一个不太好的替代方案是在我的 BackgroundWorker 派生类上添加一个公共成员“WasCancelled”,可以在 OnDoWork 捕获块中设置为 true (Me.WasCancelled = Me.CancellationPending)。然后可以在完成的回调中使用该成员。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 2016-06-18
相关资源
最近更新 更多