可以在不同的线程上多次抛出一个C#异常吗?

时间:2014-12-29 20:52:46

标签: c# .net multithreading exception clr

我有一个实现供应商/消费者模式的C#服务器。该服务器有一个供应商线程,可以生成一些数据。几个消费者线程消耗数据。正确锁定对数据的访问,以便一切正常。但有时供应商线程无法获取数据。在这种情况下,它会抛出异常。该异常在同一个线程中捕获。但是在发生异常之后,必须在每个使用者线程上抛出相同的异常。所以我有一个问题:在多个线程上多次抛出一个异常对象是否安全?我知道CLR Exception和所有继承Exception的类必须具有[Serializable]属性。这可能表示Exception对象在throw时被序列化,但我找不到任何关于此的信息。

2 个答案:

答案 0 :(得分:2)

  

在多个线程上多次抛出一个异常对象是否安全?

是的,假设你的异常对象是线程安全的,这是安全的。只要确保在多个线程上重新抛出的Exception对象本身就是线程安全的,那么在多个位置重复使用同一个对象就没有问题 * 。 / p>

但是,每个使用者线程在响应原始异常时抛出自己的异常可能是个更好的主意,并将原始异常用作构造函数中的innerException参数。内部异常将在所有线程之间保持共享,但嵌套结构将更好地反映从捕获异常的用户的角度发生的事情。

如果您要重新抛出原始异常,捕获它的用户将只能找到原始的thrower,即 producer 线程。这可能会让人感到困惑,因为它们会从使用者线程中收到异常,因此他们很难将导致异常的事件链拼凑在一起,因为堆栈跟踪将会关闭。

另一方面,嵌套异常来自消费者线程,但它们也提供innerException作为根本原因,因此捕获者可以更好地了解发生了什么。

  

我知道CLR Exception和所有继承Exception的类必须具有[Serializable]属性。这可能表示Exception对象在throw时被序列化,但我找不到任何关于此的信息。

this Q&A中描述了添加[Serializable]属性的原因。它对同一应用程序域中多个线程上的异常的可用性没有影响。

* 假设重新抛出发生在不同线程上相同方法的同一位置。

答案 1 :(得分:1)

异常可以被序列化,但它不必。如果必须使用Remoting跨越AppDomains,它将被序列化,但在您的场景中似乎并非如此。

除此之外,通常的线程和同步问题也适用:例外情况本质上是线程安全的,如果它们只在构造函数中设置readonly状态(通常就是这种情况)。

还有一件事:每当你重新抛出它时,你都会覆盖你的单个异常实例的堆栈跟踪。投掷它的最后位置获胜。因此,将您的异常包装在另一个异常中可能是个更好的主意(例如TargetInvocationException)。