代码之家  ›  专栏  ›  技术社区  ›  Dave

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

  •  1
  • Dave  · 技术社区  · 14 年前

    这个问题已经被提过很多次了,但是我想再问一遍,因为我在这里读到了一些我觉得不合适的东西(可能是因为其中一个与.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;
      }
    }
    

    好吧,正如Hans所说,不管我从线程抛出异常--period,它都会引起问题。我能够测试这个案例,并且确信,异常会被抛出,如果你点击F5,它会被一次又一次地抛出,并且永远不会终止线程。我不理解这种特殊的行为——它只是在运行调试器时的工作方式吗?我想这意味着我必须检查这个方法是被称为sync还是async。如果同步,则抛出错误。如果异步,则引发事件。

    也许更好的方法是强制客户机总是用事件处理错误,而不是捕获异常?有人对这种方法有想法吗?

    2 回复  |  直到 7 年前
        1
  •  1
  •   Dan Bryant    14 年前

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

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

        2
  •  2
  •   Hans Passant    14 年前

    不知道你想用这个代码证明什么。只需为编写一个异常处理程序AppDomain.Current.UnhandledException未处理异常并记录或显示e的值。例外对象ToString().

    如果你真的在沉思 处理 例外的是,你有完全不同的一壶鱼要炒。你有一些代码在一个随机点运行和消亡。你不知道它进展到了什么程度,你的程序状态被这个线程改变了多少。处理异常需要恢复程序状态,撤消线程所做的任何操作。无论您编写什么样的事件处理程序来处理“it bombed”事件,都不可能猜到恢复状态需要做什么,因为它对线程的了解还不够。它只知道没用。恢复状态需要由线程本身完成。

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