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

一个C#异常是否可以在不同的线程上多次抛出?,c#,.net,multithreading,exception,clr,C#,.net,Multithreading,Exception,Clr,我有一个C#服务器,它实现了供应商/消费者模式。此服务器有一个生成某些数据的供应商线程。几个使用者线程使用数据。对数据的访问已正确锁定,因此一切正常。但有时供应商线程无法获取数据。在本例中,它抛出一个异常。在同一线程中捕获异常。但是在异常发生之后,有必要在每个使用者线程上抛出相同的异常。所以我有一个问题:在多个线程上多次抛出一个异常对象安全吗?我知道CLR异常和继承异常的所有类必须具有[Serializable]属性。这可能表明异常对象是在抛出时序列化的,但我找不到任何有关这方面的信息 在多个线

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

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

是的,它是安全的,假设您的异常对象是线程安全的。只要确保在多个线程上重新抛出的
Exception
对象本身是线程安全的,那么在多个位置重用同一对象就不会有问题*

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

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

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

我知道CLR异常和继承异常的所有类必须具有
[Serializable]
属性。这可能表明异常对象是在抛出时序列化的,但我找不到任何有关这方面的信息

添加
[Serializable]
属性的原因如中所述。它不会影响同一应用程序域中多个线程上异常的可用性

*假设在不同线程上的同一方法的同一位置发生重试。

可以序列化异常,但不必序列化。例如,如果它必须使用远程处理跨AppDomains,它将被序列化,但在您的场景中,情况似乎并非如此

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


不过,还有一件事:无论何时重试,都将覆盖单个异常实例的堆栈跟踪。最后一个投掷它的位置获胜。因此,最好将您的异常包装到另一个异常中(例如TargetInvocationException)。

异常必须是可序列化的,因为它们可以跨越AppDomain边界。它与螺纹没有任何关系。但是,如果再次抛出异常,则会吹走堆栈跟踪。最好将其包装在一个新的异常中,并抛出需要通知的每个线程。这个问题似乎很有趣,但不确定您的要求到底是什么。您可能是对的,但我的消费者等待适当类型的异常。我最好通过序列化/反序列化并抛出副本来复制异常。@Slava这也可以,尽管它不允许保留原始堆栈跟踪。不过,您可以使用相同的类型和所有内容创建同一异常的全新实例,但将原始异常作为其
innerException
,以分别保留两个堆栈跟踪。我不知道供应商生成的异常类型。我知道我可以使用反射来获取类型名并构造相同的异常,但这会使代码的可维护性降低,变得更复杂。我实际上并不需要供应商的堆栈。自定义异常类型具有使用者所需的所有信息