在C#中是否有一个很好的方法可以在给定的线程上抛出exception

我想写的代码是这样的:

void MethodOnThreadA() { for (;;) { // Do stuff if (ErrorConditionMet) ThrowOnThread(threadB, new MyException(...)); } } void MethodOnThreadB() { try { for (;;) { // Do stuff } } catch (MyException ex) { // Do the right thing for this exception. } } 

我知道我可以让线程B以线程安全的方式定期检查线程A是否设置了一个标志,但这会使代码更复杂。 有没有更好的机制可供我使用?

这是一个更加充实的定期检查示例:

 Dictionary exceptionDictionary = new Dictionary(); void ThrowOnThread(Thread thread, Exception ex) { // the exception passed in is going to be handed off to another thread, // so it needs to be thread safe. lock (exceptionDictionary) { exceptionDictionary[thread] = ex; } } void ExceptionCheck() { lock (exceptionDictionary) { Exception ex; if (exceptionDictionary.TryGetValue(Thread.CurrentThread, out ex)) throw ex; } } void MethodOnThreadA() { for (;;) { // Do stuff if (ErrorConditionMet) ThrowOnThread(threadB, new MyException(...)); } } void MethodOnThreadB() { try { for (;;) { // Do stuff ExceptionCheck(); } } catch (MyException ex) { // Do the right thing for this exception. } } 

这不是一个好主意

本文讨论ruby的超时库。 它会跨线程抛出exception。

它解释了如何从根本上打破这样的事情。 它不仅仅是在ruby中被破坏,它在任何可以跨线程抛出exception的地方都会被破坏。

简而言之,可以(并且确实)发生的是:

ThreadA中:

 At some random time, throw an exception on thread B: 

ThreadB:

 try { //do stuff } finally { CloseResourceOne(); // ThreadA's exception gets thrown NOW, in the middle // of our finally block and resource two NEVER gets closed. // Obviously this is BAD, and the only way to stop is to NOT throw // exceptions across threads CloseResourceTwo(); } 

您的“定期检查”示例很好,因为您实际上并未在线程之间抛出exception。
你只是设置了一个标志,上面写着“下次你看这个标志时会抛出一个exception”,这很好,因为它不会受到“可以在你的捕获中间抛出或最终阻塞”的问题。
但是,如果您要这样做,您也可以设置一个“exitnow”标志,并使用它并节省创建exception对象的麻烦。 一个挥发性的bool可以正常工作。

有很多问题可以通过其他机制抛出线程,例如中止线程等,你应该找到另一种方法。

一个例外是一种机制,用于表示某个进程遇到了一些无法处理的特殊情况。 您应该尽量避免编写代码,以便使用exception来表示其他人遇到过exception情况。

其他线程很可能不知道如何在代码抛出exception的情况下处理exception。

简而言之,您应该找到一些其他机制来中止您的线程而不是使用exception。

使用事件对象或类似物告诉线程中止其处理,这是最好的方法。

在研究另一个问题时,我遇到了这篇文章,它让我想起了你的问题:

使用Rotor管道ThreadAbortException的深度

它显示了.NET实现Thread.Abort()的旋转 – 可能任何其他跨线程exception都必须类似。 (Yeech!)

猎户座爱德华兹所说的并不完全正确:不是“唯一”的方式。

 // Obviously this is BAD, and the only way to stop is to NOT throw // exceptions across threads 

在C#中使用CER( 约束执行区域 )允许您将资源作为primefaces操作发布,从而保护代码免受线程间exception的影响。 .NET Framework的几个类使用此技术,它与Windows的本机API一起使用,其中未发布的句柄可能导致内存泄漏。

请参阅http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

以下示例说明如何使用PrepareConstrainedRegions方法可靠地设置句柄。 要可靠地设置指定预先存在的句柄的句柄,必须确保本机句柄的分配以及SafeHandle对象中该句柄的后续记录是primefaces的。 这些操作之间的任何失败(例如线程中止或内存不足exception)都将导致本机句柄泄露。 您可以使用PrepareConstrainedRegions方法确保句柄不会泄露。

很简单:

 public MySafeHandle AllocateHandle() { // Allocate SafeHandle first to avoid failure later. MySafeHandle sh = new MySafeHandle(); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally // this finally block is atomic an uninterruptible by inter-thread exceptions { MyStruct myStruct = new MyStruct(); NativeAllocateHandle(ref myStruct); sh.SetHandle(myStruct.m_outputHandle); } return sh; } 

我很想知道你为什么要这样做。 没有一种简单的方法可以做到这一点,因为这不是一个好习惯。 您应该回到您的设计并找出一种更清洁的方法来实现最终目标。

我认为这不是一个好主意。对此问题采取另一种解决方法 – 尝试使用其他机制(如共享数据)在线程之间发出信号。

和其他人一样,我不确定这是一个好主意,但如果你真的想这样做,那么你可以创建一个SynchronizationContext的子类,允许发布委托给目标线程(如果它是一个WinForms线程的工作)为你完成,因为这样的子类已经存在)。 目标线程必须实现某种类型的消息泵,但要接收代理。

@Orion Edwards

我指出你在finally块中抛出exception的观点。

但是,我认为有一种方法 – 使用另一个线程 – 使用这种exception中断的想法。

线程A:

 At some random time, throw an exception on thread C: 

线程B:

 try { Signal thread C that exceptions may be thrown //do stuff, without needing to check exit conditions Signal thread C that exceptions may no longer be thrown } catch { // exception/interrupt occurred handle... } finally { // ...and clean up CloseResourceOne(); CloseResourceTwo(); } 

线程C:

  while(thread-B-wants-exceptions) { try { Thread.Sleep(1) } catch { // exception was thrown... if Thread B still wants to handle exceptions throw-in-B } } 

或者这只是愚蠢的?