如何在单独的 std::thread 完成之前暂停异常传播?
How do I pause exception propagation until a separate std::thread completes?
我的代码在主线程中被拆分为一部分 运行,另一部分在单独的线程中。主线程最后等待 thread.join()
。
现在,如果主线程抛出异常,即使我尝试捕获异常,我的程序也会立即终止。我将其追踪到 std::~thread
,如果线程仍然是 运行(可连接),我会很不高兴。
在这种情况下,我希望异常等到线程自然退出,然后继续传播。我怎么做?我需要用某种 joining_thread
来包装 std::thread
吗?
#include <iostream>
#include <thread>
class foo
{
public:
foo(const char* name) : m_name(name) {}
~foo() { std::cout << "~foo - " << m_name << "\n"; }
private:
std::string m_name;
};
void doInThread()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "doInThread\n";
}
int doit()
{
foo fooBefore("main before thread"); // d'tor is never called
auto thread = std::thread(doInThread);
foo fooAfter("main after thread");
// Do stuff, which might throw
throw std::exception("Something happened in main");
thread.join();
}
int main()
{
try
{
doit();
}
catch (std::exception ex)
{
std::cout << "Exception: " << ex.what() << "\n"; // Never happens - program terminates beforehand
}
}
您的程序已通过调用 std::terminate
函数中止。
当抛出异常时,堆栈展开,这意味着在调用 throw
之前创建的所有局部变量都将被删除。当线程的dtor被调用时,线程处于joinable状态,std::terminate
被调用according to thread reference.
使用 RAII 创建对象,其 dtor 将加入您的线程。
template<class F>
struct Cleaner {
Cleaner(F in) : f(in) {}
~Cleaner() { f(); }
F f;
};
template<class F>
Cleaner<F> makeCleaner(F f) {
return Cleaner<F>(f);
}
int doit()
{
foo fooBefore("main before thread");
auto thread = std::thread(doInThread);
auto cleaner = makeCleaner([&thread](){ thread.join(); });
foo fooAfter("main after thread");
throw std::runtime_error("Something happened in main");
// without throw statement, dtor of cleaner instance would be called here
}
现在,在展开堆栈时,将按如下方式调用析构函数:fooAfter
、cleaner
(等待线程完成)和 fooBefore
.
我的代码在主线程中被拆分为一部分 运行,另一部分在单独的线程中。主线程最后等待 thread.join()
。
现在,如果主线程抛出异常,即使我尝试捕获异常,我的程序也会立即终止。我将其追踪到 std::~thread
,如果线程仍然是 运行(可连接),我会很不高兴。
在这种情况下,我希望异常等到线程自然退出,然后继续传播。我怎么做?我需要用某种 joining_thread
来包装 std::thread
吗?
#include <iostream>
#include <thread>
class foo
{
public:
foo(const char* name) : m_name(name) {}
~foo() { std::cout << "~foo - " << m_name << "\n"; }
private:
std::string m_name;
};
void doInThread()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "doInThread\n";
}
int doit()
{
foo fooBefore("main before thread"); // d'tor is never called
auto thread = std::thread(doInThread);
foo fooAfter("main after thread");
// Do stuff, which might throw
throw std::exception("Something happened in main");
thread.join();
}
int main()
{
try
{
doit();
}
catch (std::exception ex)
{
std::cout << "Exception: " << ex.what() << "\n"; // Never happens - program terminates beforehand
}
}
您的程序已通过调用 std::terminate
函数中止。
当抛出异常时,堆栈展开,这意味着在调用 throw
之前创建的所有局部变量都将被删除。当线程的dtor被调用时,线程处于joinable状态,std::terminate
被调用according to thread reference.
使用 RAII 创建对象,其 dtor 将加入您的线程。
template<class F>
struct Cleaner {
Cleaner(F in) : f(in) {}
~Cleaner() { f(); }
F f;
};
template<class F>
Cleaner<F> makeCleaner(F f) {
return Cleaner<F>(f);
}
int doit()
{
foo fooBefore("main before thread");
auto thread = std::thread(doInThread);
auto cleaner = makeCleaner([&thread](){ thread.join(); });
foo fooAfter("main after thread");
throw std::runtime_error("Something happened in main");
// without throw statement, dtor of cleaner instance would be called here
}
现在,在展开堆栈时,将按如下方式调用析构函数:fooAfter
、cleaner
(等待线程完成)和 fooBefore
.