线程时的异常 - 线程之间的传播?

Posted

技术标签:

【中文标题】线程时的异常 - 线程之间的传播?【英文标题】:Exception when threading - propagation between threads? 【发布时间】:2012-07-17 17:20:42 【问题描述】:

如果我有以下情况:

    Execute() 创建一个新线程并在其中执行函数 GetSession()。 Execute() 在自己的线程中再次执行 GetSession()。 Execute() 从 (1) 加入线程。

我的问题是:

如果 GetSession() 从 (1) 中产生的线程抛出异常,而 Execute() 正在运行的线程当前正在运行 GetSession() 本身,会发生什么?

是否从额外线程重新抛出的异常传播到 Execute() 并导致它转到其处理程序即使它来自不同的线程?


这里有一些示例代码来演示这个问题:

我只是在这里的窗口中做了这个(这是一个模型),所以请原谅语法错误。

public void Execute()

    //Some logon data for two servers.
    string server1 = "x", server2 = "y", logon = "logon", password = "password";

    //Varialbes to store sessions in.
    MySession session1, session2;

    try
    
        //Start first session request in new thread.
        Thread thread = new Thread(() =>
            session1 = GetSession(server1, logon, password));
        thread.Start();

        //Start second request in current thread, wait for first to complete.
        session2 = GetSession(server2, logon, password));
        thread.Join();
    
    catch(Exception ex)
    
        //Will this get hit if thread1 throws an exception?
        MessageBox.Show(ex.ToString());
        return;
    


private MySession GetSession(string server, string logon, string password)

    try
    
        return new MySession(server, logon, password);
    
    catch(Exception Ex)
    
        throw(Ex);
    

【问题讨论】:

也许是一个显而易见的问题,但为什么不试试呢? 实际上,我遇到了一个更复杂的情况,归结为这一点,但是当另一个线程遇到异常时,调试器会不断中断并突出显示重新抛出。我不确定这是否是由于调试器的设置造成的,或者异常不应该传播,所以我想我会问:) 我敢肯定我可以写一个小实验,但它是很高兴得到专家的解答。 【参考方案1】:

如果 GetSession() 从 (1) 中产生的线程抛出异常,而 Execute() 正在运行的线程当前正在运行 GetSession() 本身,会发生什么?

线程版本将引发未处理的异常,这将触发AppDomain.UnhandledException。除非在此处明确处理,否则它将关闭应用程序。

是否从额外线程重新抛出的异常传播到 Execute() 并导致它转到其处理程序,即使它来自不同的线程?

没有。它将未处理。


请注意,这是 TPL 的优势之一。如果您使用任务而不是线程,您可以将异常传播回主线程​​:

try

    //Start first session request in new thread.
    Task<Session> task = Task.Factory.StartNew(() => GetSession(server1, logon, password));

    //Start second request in current thread, wait for first to complete.
    session2 = GetSession(server2, logon, password));
    session1 = task.Result; // This blocks, and will raise an exception here, on this thread

catch(Exception ex)

    // Now this will get hit
    MessageBox.Show(ex.ToString());
    return;

但请注意,这将是 AggregateException 和 requires special handling。

【讨论】:

感谢您对 UnhandledException 的引用。 @w00te 我编辑向您展示如何通过 TPL 很好地处理这个问题。 您还可以使用 Task 的 .ContinueWith() 方法在单独的新后台任务中处理异常,从而避免阻塞情况(如果不希望出现阻塞情况。)

以上是关于线程时的异常 - 线程之间的传播?的主要内容,如果未能解决你的问题,请参考以下文章

异常传播和 std::future

如何避免从工作线程到 GUI 线程的主体传播

一个线程中对 MOC 属性的更改未传播到主线程

在线程中传播系统调用中断

将 ThreadLocal 传播到从 ExecutorService 获取的新线程

Python:防止信号传播到子线程