通常的做法是使用警卫,RAII和try / catch块来确保在所有情况下最终都会加入一个线程。但是,那些意味着分离的线程呢?
void aFunction() {
std::thread t {someOtherFunction}; // someOtherFunction may throw!!!
t.detach;
}
我是否应该使用一些异常处理机制来确保t
即使在例外的情况下也能正确分离,或者它是否真的无关紧要?
答案 0 :(得分:4)
std::thread t {someOtherFunction}; // someOtherFunction may throw!!
如果someOtherFunction
可以抛出,则需要在该函数中处理异常。如果不是,则默认行为是在异常“转义”线程函数时调用std::terminate
。
std::thread
对象构造和std::thread::detach
本身也可以抛出,因此这些异常需要由aFunction()
处理。
如果线程对象不可连接,则抛出detach()
方法。因此,如果您希望避免处理此异常,可以在尝试分离之前添加测试以查看该线程是否可连接。
if (t.joinable())
t.detach;
你被称为detach()
这一事实表明你不希望在以后阶段“加入”(同步)线程,它基本上会照顾好自己。
与大多数异常处理问题一样,您将如何处理抛出的异常?如果无法处理异常,则要么不捕获它,要么捕获它,记录它并重新抛出它(或者调用std::terminate
)。
答案 1 :(得分:1)
The fact that ~thread calls std::terminate if not joined is considered a flaw in the standard.
Scott Meyers建议使用ThreadRAII
包装器连接析构函数中的线程(如果它仍然可以连接):
class ThreadRAII {
public:
ThreadRAII(std::thread&& thread): t(std::move(thread)) {}
~ThreadRAII() { if (t.joinable()) (t.join(); }
private:
std::thread t;
};
如果someOtherFunction
在另一个线程中抛出异常并且没有人捕获该异常,则调用std::terminate
。
使用std::current_exception
和std::rethrow_exception
来捕获异常,将其传输到另一个线程并重新抛出它。 E.g:
void thread_function(std::exception_ptr* exception)
try {
throw std::runtime_error("test exception");
}
catch(std::exception& e) {
*exception = std::current_exception();
}
int main() {
// Thread creation.
std::exception_ptr other_thread_exception;
std::thread t{thread_function, &other_thread_exception};
// Thread termination.
t.join();
if(other_thread_exception)
std::rethrow_exception(other_thread_exception);
}
答案 2 :(得分:0)
我是否应该使用一些异常处理机制来确保
t
即使在例外的情况下也能正确分离,或者它是否真的无关紧要?
你是什么意思“即使在例外的情况下也能正确分离”?你担心什么样的“不当”分离?
立即拆除它,并且不存在异常安全问题:
std::thread t{something};
t.detach();
如果t
的构造函数抛出,则无法分离。如果没有,则将其作为下一个语句分离,并且在此之前没有任何东西可以抛出。
一旦它被分离,它就不能连接,所以你不需要RAII或任何其他机制来确保它在你离开范围之前加入或分离。