2

I have a C# server that implements supplier/consumer pattern. This server has a supplier thread that produces some data. Several consumer threads consume the data. Access to the data is properly locked so everything works fine. But sometimes the supplier thread cannot get the data. In this case it throws an exception. The exception is caught within the same thread. But after the exception is occurred it is necessary to throw this same exception on every consumer thread. So I have a question: is it safe to throw one exception object several times on multiple threads? I know that CLR Exception and all classes that inherit Exception must have [Serializable] attribute. This maybe an indication that Exception object is serialized on throwing, but I couldn't find any info on this.

Slava
  • 985
  • 4
  • 10
  • 2
    Exceptions must be serializable because they can cross AppDomain boundaries. It doesn't have any bearing on threads. However, if you throw an exception again you will blow away the stack trace. Better to wrap it in a new exception and throw on each thread that needs to be notified. – Mike Zboray Dec 29 '14 at 21:12
  • The problem seems interesting, but not sure exactly what you asking. – leppie Dec 29 '14 at 21:12

2 Answers2

2

is it safe to throw one exception object several times on multiple threads?

Yes, it is safe, assuming that your exception objects are thread-safe. As long as you make sure that Exception object that you re-throw on multiple threads is itself thread-safe, there will be no issues with reusing the same object in multiple places*.

However, it is probably a better idea for each consumer thread to throw its own exception in response to the original exception, and use the original exception as the innerException parameter in the constructor. The inner exception would remain shared among all threads, but the nested structure would better reflect what happened from the point of view of the user who catches the exception.

If you would re-throw the original exception, the users who catch it would be able to find only the original thrower, which is the producer thread. This may be confusing, because they receive the exception from a consumer thread, so they would have hard time piecing together the chain of events that lead to the exception, because the stack trace would be off.

Nested exceptions, on the other hand, come from consumer threads, but they also provide innerException as their root cause, so the catcher gets a better idea of what exactly has happened.

I know that CLR Exception and all classes that inherit Exception must have [Serializable] attribute. This maybe an indication that Exception object is serialized on throwing, but I couldn't find any info on this.

The reason you add [Serializable] attribute is described in this Q&A. It has no effect on usability of exceptions on multiple threads within the same app domain.

*Assuming that rethrowing happens in the same spot of the same method on different threads.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 675,664
  • 71
  • 998
  • 1,399
  • You are probably right, but my consumers wait for exceptions of proper types. I'd better copy the exception by serializing/deserializing and throw the copy. – Slava Dec 29 '14 at 21:54
  • @Slava That would work, too, although it wouldn't let you preserve the original stack trace. You could make a brand-new instance of the same exception, though, with the same type and everything, but put the original exception as its `innerException` to preserve both stack traces separately. – Sergey Kalinichenko Dec 29 '14 at 21:59
  • I don't know exactly the exception type the supplier produced. I know I can use reflection to get a type name and construct same exception, but this would make the code less maintainable an more complex. And I don't actually need the supplier stack. The custom exception type has all info consumers need – Slava Dec 29 '14 at 22:08
1

An exception can be serialized, but it doesn't have to. It will be serialized if it has to cross AppDomains using Remoting for example, but in your scenario that doesn't seem to be the case.

Aside from that, the usual threading and synchronization issues apply: Exceptions are inherently thread safe, if they only set readonly state in the constructor (which usually is the case).

One more thing, though: You're going to overwrite the stack trace of your single exception instance whenever you rethrow it. The last location throwing it wins. Therefore, it's probably a better idea to wrap your exception in another one (e.g. TargetInvocationException).

Frank
  • 4,328
  • 11
  • 27