提问人:Andrey Epifantsev 提问时间:11/8/2023 更新时间:11/8/2023 访问量:53
引发异常时调用 std::future 析构函数
Calling the std::future destructor when an exception is thrown
问:
有这样的代码:
#include <chrono>
#include <future>
#include <iostream>
using namespace std::chrono_literals;
int main()
{
try {
std::atomic<bool> stopTask;
stopTask.store(false, std::memory_order_seq_cst);
auto future = std::async([&stopTask]() {
for (int i = 0; i < 20; ++i)
{
if (stopTask.load(std::memory_order_seq_cst))
break;
std::this_thread::sleep_for(500ms); // Imitation of useful task.
}
});
// Some useful work in the main thread.
throw std::runtime_error("Error"); // Oops! Something went wrong in the main thread.
// Normal shutdown.
stopTask.store(true, std::memory_order_seq_cst);
future.get();
}
catch (...)
{
std::cout << "Exception caught" << std::endl;
}
}
我使用 std::async 在单独的线程中运行一个长时间运行的任务,并在其上接收 std::future。之后,在主线程中抛出异常。堆栈展开开始,并调用析构函数。一旦它到达 std::future 析构函数,堆栈展开就会停止,主线程就会阻塞,直到第二个线程完成。
看起来有些不对劲。我看到过一些建议,即尽可能快地制作析构函数,而不是在其中执行长时间的操作。但是这里的析构函数非常慢,堆栈展开需要很长时间。
问题:堆垛放卷需要这么长时间是正确的吗?也许我做错了什么,实际上需要做一些不同的事情?在这种情况下,最佳实践是什么?
在这个特定的代码中,std::future 析构函数可以通过像 RAII 一样围绕 std::atomic stopTask 创建一个包装类来加速,这会在析构函数中将 stopTask 设置为 true。但执行析构函数仍可能需要长达 500 毫秒的时间。这不能再加快了,因为在我的应用程序中,真正的最小操作需要很多时间。
答: 暂无答案
评论
future
std::async