处理源自线程的错误的标准方法

时间:2010-08-20 13:51:51

标签: c# multithreading events exception exception-handling

这个问题已经多次提出,但是我想再问一遍,因为我在这里看到了一些对我来说不合适的事情(可能是因为一个与.NET CF有关) ,我要求验证我认为合理的具体方法,并感谢您提供的任何反馈。

无论如何,情况就像每个人一样 - 我想处理来自线程的错误。目前,我的代码工作正常,因为我从一个线程抛出异常,但我使用的是Invoke,而不是BeginInvoke。

你可能想知道,“为什么他会创建一个线程,然后调用Invoke?为什么不调用一个函数?”。问题是我希望通过一个参数来赋予调用者灵活性,该参数指示操作是同步还是异步。

作为测试,我已经在异步操作模式下对其进行了测试,并且正如预期的那样,它以静默方式失败,并且应用程序在调试器中因工作线程抛出异常而死亡。

为了确保我对线程中的异常行为有基本的了解,以及disprove the statement in this question on SO(至少就.NET 3.5而言),我在WPF应用程序中编写了一些测试代码:

已删除

代码

因此,似乎在主线程中处理来自另一个线程的事件应该没有问题。

如果您同意我上面的测试,我的问题就是这样 - 编写我的方法是否可以接受,它提供同步和异步行为,其中所有业务逻辑都包含在try / catch块中?内部错误被困在线程内部,如果是同步调用,只需抛出异常,如果是异步调用,只需引发事件?在上面的示例代码中,我也在引发事件后抛出异常。我不确定这是否或为什么会给我带来任何问题。

Pseudo-pseudocode:

TestFunc(async);

private TestFunc(bool async)
{
  try {
    throw new MyAppException("error occurred.");
  } catch(MyAppException ex) {
    async ? RaiseErrorEvent : throw;
  }
}

更新

好吧,正如汉斯所说的那样,无论如何从线程中抛出异常,它都会引起问题。我能够测试这个案例,当然,异常会被抛出,如果你点击F5,它会被反复抛出而永远不会终止线程。我不明白这种特殊行为 - 它是通过调试器运行时的工作原理吗?我想这意味着我必须检查该方法是否被称为同步或异步。如果同步,则抛出错误。如果是异步,请举起事件。

也许更好的方法是强制客户端始终处理事件错误,而不是捕获异常?有人对这种方法有什么看法吗?

2 个答案:

答案 0 :(得分:2)

不确定您要使用此代码证明什么。只需为AppDomain.Current.UnhandledException编写一个异常处理程序,并记录或显示e.ExceptionObject.ToString()的值。

如果您正在考虑实际处理例外,那么您将有一个完全不同的鱼缸来煎炸。你有一些代码可以随机运行并死掉。你真的不知道它有多远,你的程序状态有多少被那个线程改变了。处理异常需要恢复程序状态,撤消线程所做的任何事情。无论你编写什么事件处理程序来处理“它被轰炸”的事件都无法猜测恢复状态需要做些什么,它对线程知之甚少。它只知道它不起作用。恢复状态需要由线程本身完成。

处理“轰炸”事件本身很困难。客户端代码甚至无法显示消息框,它很容易消失在主窗口后面。不允许直接更新UI。需要将调用封送到UI线程。最好的方法是将其留给客户端代码来决定如何通知它。 FileSystemWatcher.SynchronizingObject属性是一个很好的模式。

答案 1 :(得分:1)

如果您正在谈论异步执行任务,最典型的模式是捕获线程中的异常并在最终同步以等待任务完成后重新抛出它。例如,IAsyncResult pattern有一个BeginX(),EndX()调用结构,您可以调用EndX()来阻塞直到完成。 EndX()调用应抛出异步操作中发生的任何异常,以便调用者可以决定如何处理它。

如果您使用的是.NET 4.0,Task Parallel Library在执行异步任务时对捕获甚至聚合异常有广泛的支持,以便启动任务的客户端可以决定如何处理它们。