安全地抛出在另一个线程C#上创建的异常

时间:2012-07-04 09:46:15

标签: c# multithreading exception thread-safety

我想在线程A中捕获异常,然后将异常对象传递给线程B,并从线程B中抛出它。这样安全吗?

主题A

try {
    // Code that throws exceptions
} catch (Exception e) {
    sendToOtherThread(e);
}

主题B

Exception e = receiveException();
throw e;

修改

为了清楚起见:我理解线程是如何工作的,以及我应该如何将对象引用从一个线程传递到另一个线程。问题更多的是从一个没有创建它的线程抛出一个异常对象是安全的,还是类Exception本身或.NET处理它的方式有问题。

5 个答案:

答案 0 :(得分:1)

如果考虑使用.NET 4.0,Task抛出的任何异常会在Task加入时自动传播到父线程。这是设计的,应该是非常安全的。看看这里:http://msdn.microsoft.com/en-us/library/dd997415.aspx

答案 1 :(得分:1)

可以重新抛出从另一个线程收到的异常(例如,在BackgroundWorker的RunWorkerCompleted事件处理程序中),但更常见的是将它包装在另一个异常中,以保留堆栈跟踪:

private void backgroundWorker1_RunWorkerCompleted(
    object sender, RunWorkerCompletedEventArgs e)
{
    // First, handle the case where an exception was thrown.
    if (e.Error != null)
    {
        throw new SomeException("... message ...", e.Error);
    }
    ...
}

答案 2 :(得分:0)

你需要改变这个:

线程B中的

Exception e = receiveException();
throw new Exception("Write something here, for example: 'Received from other thread'", e); // so you keep the stack trace

但是我要注意警告(我不完全确定这是100%安全的)。

答案 3 :(得分:0)

它应该是安全的,但很可能会终止线程B.

您的解决方案仅取决于您如何将异常对象从线程A传递到线程B. 如果要将其放在共享资源中,则需要锁定并释放该特定共享资源。除此之外,您的代码没有任何不安全因素。

只要您不访问线程中的任何共享资源,其他一切都应该是安全的。

答案 4 :(得分:0)

Exception是一个类,因此是一个标准引用类型,如果你想在线程之间传递它(听起来有点奇怪),你需要确保没有其他人试图修改实例(特别是如果你创建自己的可变异常类型。)

解决方案A
你可以做一个Producer-Consumer拉模型

BlockingCollection<Exception> bc = new BlockingCollection<Exception>();

// thread A - Producer
try
{
    ...
}
catch(Exception ex)
{
    bc.Add(ex);
}


//thread B - Consumer
try
{
    // Consume bc
    while (true)
    {
        var ex = bc.Take();
        //thread sleep
    }
}
catch (InvalidOperationException)
{
    // IOE means that Take()
    // was called on a completed collection and no
    // No more exceptions, restart checking    
}

解决方案B
但是可能更好的想法是不使用拉模型,因为在这种情况下它可能浪费资源,而是推送具有线程安全可观察集合的模型。