2016-12-29 97 views
0

我有一个处理多线程C++代码中的异常的问题。以下程序以terminate called without an active exception Aborted (core dumped)退出。std ::线程和异常处理

#include <thread> 
#include <iostream> 
#include <stdexcept> 

struct Thing { 

    void runComponent() 
    { 
     throw std::runtime_error("oh no!\n"); 
    } 

    void runController() 
    { 
     while (true) {} 
    } 

    void run() 
    { 
     auto control_thread = std::thread([this] { runController(); }); 

     runComponent(); 

     if (control_thread.joinable()) 
      control_thread.join(); 
    } 
}; 

int main() 
{ 
    try { 
     Thing thing; 
     thing.run(); 
    } catch (std::runtime_error &ex) { 
     std::cerr << ex.what(); 
    } 
} 

相反,我想处理异常的try catchmain()。我知道异常不会(通常)在线程之间传递,因为线程每个都有自己的堆栈。这里的问题(在我看来)是即使在非分叉线程上生成异常也没有被处理。如果我注释掉run()control_thread有关的行,那么一切正常。

与铿锵-3.8和-std=c++11 main.cpp -lpthread编译。

+0

@Curious也许。我知道'exception_ptr'。但这里的问题(我认为)是thrower(runComponent)实际上是在主线程上。即使在这种情况下,我是否需要使用异常指针? – jonnew

+0

在下面的答案中回答!我误解了这个问题 – Curious

回答

1

这里的问题是您在run()方法中创建的线程上既没有呼叫detach()join()。这是C++线程中的错误。见When should I use std::thread::detach?

如果你改变你的代码到以下任一则一切工作正常

#include <thread> 
#include <iostream> 
#include <stdexcept> 

struct Thing { 

    void runComponent() 
    { 
     throw std::runtime_error("oh no!\n"); 
    } 

    void runController() 
    { 
     return; 
    } 

    void run() 
    { 
     auto control_thread = std::thread([this] { runController(); }); 
     // either of the following two will work 
     // control_thread.join(); 
     control_thread.detach(); 

     runComponent(); 
    } 
}; 

int main() 
{ 
    try { 
     Thing thing; 
     thing.run(); 
    } catch (std::runtime_error &ex) { 
     std::cerr << ex.what(); 
    } 
} 

它看起来就像你想要的是一个分离的东西,这就是为什么我脱离线程在上面的例子。如果这不是你想要的,你可能需要一些其他方式来处理线程。如果你想让主线程和其他线程独立工作,那么你需要一些其他的同步。

+0

是的,这是有效的。我想我想要分离,但我注意到在你提供的SO链接的答案中提出的观点“除非你需要更多的灵活性,并且愿意提供一个同步机制来等待你自己的线程完成,其中你可能会使用分离“。在这个特殊情况下,这是什么意思?如果我使用detach,会释放'runController()'分配的资源吗? – jonnew

+0

此外,“C++线程错误”是否指标准库实现? – jonnew

+0

@jonnew我认为这意味着如果你想要一些自定义的方式来处理异常,那么你将不得不手动使用锁来实现它。最简单的事情是按照发生异常的顺序创建一个线程列表,其中包含线程的线程标识符。我不认为这是相关 – Curious