【问题标题】:Preventing thread from calling std::terminate() on detach after handled exception处理异常后防止线程在分离时调用 std::terminate()
【发布时间】:2018-03-05 20:39:09
【问题描述】:

我有自己的线程类,旨在帮助安全地管理异常。它看起来像这样:(为简单起见,跳过了其他构造函数和互斥体)

class ExceptThread
    : public std::thread {
public:
    template<typename Func, typename... Args>
    ExceptThread(Func&& f, Args&&... args)
        : std::thread([] (Args&&... args) {
        try {
            return f(args...);
        } catch(...) {
            exc = std::current_exception();
        }
    }, args...) { }
    // skipped other constructors etc.
    //...    
    void check() { 
        if(exc) { 
            std::exception_ptr tmp = exc; 
            exc = nullptr; 
            std::rethrow_exception(tmp); 
        } 
    }

private:
    std::exception_ptr exc;
};

这个类的意思是这样使用:

ExceptThread et([] { std::this_thread::sleep_for(5s); throw std::runtime_error("Ugly exception"); });

try {
    while(/*...*/) {
        // main loop
        et.check();
    }
} catch(std::exception& e) {
    // do sth
}

问题:

当线程抛出异常时,它被catch(...) 捕获并保存到exc,一切都很好。但是当执行更进一步时,std::terminate 会被调用,就像没有捕获到异常一样。我还尝试在捕获异常后暂停子线程(例如Sleep(INFINITE)),但在主线程中的堆栈展开期间在分离std::thread::~thread() 中的线程时调用std::terminate()。如何防止系统这样做?

平台:MSVC

类似:How can I propagate exceptions between threads?

【问题讨论】:

  • 线程正常退出时;它不调用 std::terminate。这意味着您的异常处理可能正在抛出......您可能想在调试器中进行调查。
  • 您的代码中有一个数据竞争,因为您从新创建的线程中修改了exc 成员变量,并通过check 从主线程中读取它成员函数。
  • 为了简单起见,我在发布的示例中跳过了同步

标签: c++ multithreading exception-handling


【解决方案1】:

您必须在销毁线程之前显式加入线程,这是为了防止在您忘记在销毁线程之前中断线程时发生潜在的死锁/崩溃(在我使用的每个实现中,std::终止消息)。

【讨论】:

  • 谢谢,就是这样。我从不认为你必须加入已经完成的线程
  • 是的,我也发现了,我认为 boost::thread 没有这个要求,从 boost 到 std 的移植破坏了我们的代码
  • @kubawal 你不必join它,另一个选择是detach它。您在回答中写道,您分离创建了线程,这非常具有误导性,因为您可能不是有意调用detach
  • @Daniel 在没有加入线程的情况下分离它会导致相同的行为
  • @DanielLangr 在这种情况下分离可能是危险的,因为如果线程仍在运行,它会在尝试访问已删除的 exc 成员时崩溃。在销毁之前加入线程的要求是为了保护你,不应该被解决。我认为在大多数实现中,加入一个已经完成的线程是一种廉价的操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-09
  • 1970-01-01
  • 2011-02-09
  • 1970-01-01
  • 2012-02-08
  • 1970-01-01
相关资源
最近更新 更多