c++ - Promise 和 set_value_at_thread_exit 的生命周期
问题描述
假设我们有以下代码:
std::promise<int> promise;
auto future = promise.get_future();
const auto task = [](auto promise) {
try {
promise.set_value_at_thread_exit(int_generator_that_can_throw());
} catch (...) {
promise.set_exception_at_thread_exit(std::current_exception());
}
};
std::thread thread(task, std::move(promise));
// use future
thread.join();
我想知道这段代码是否正确和安全,如果不是,为什么。
使用 GCC 编译时它似乎工作正常,但使用 MSVC (2017) 编译时崩溃(不打印任何消息)。我的猜测是发生崩溃是因为promise
内部的局部变量task
超出范围并且过早销毁。如果我删除_at_thread_exit
后缀,此代码将按预期工作(或似乎工作)。当 Promise 被捕获时,它也能正常工作:
const auto task = [p = std::move(promise)]() mutable {
/*...*/
};
解决方案
为什么你的代码会产生问题?让我们从“何时_at_thread_exit
写入和的共享状态std::future
?std::promise
”的答案开始。它发生在销毁所有线程局部变量之后。您的 lambda 在线程内被调用,并且在其范围离开后,promise 已经被销毁。但是当调用你的 lambda 的线程有一些线程局部变量时会发生什么?好吧,写入将在std::promise
对象销毁后发生。实际上,其余的在标准中确实是未定义的。似乎可以在销毁后将数据传递到共享状态,std::promise
但信息实际上并不存在。
最简单的解决方案当然是这样的:
std::promise<int> promise;
auto future = promise.get_future();
const auto task = [](std::promise<int>& promise) {
try {
promise.set_value_at_thread_exit(int_generator_that_can_throw());
} catch (...) {
promise.set_exception_at_thread_exit(std::current_exception());
}
};
std::thread thread(task, std::ref(promise));
// use future
thread.join();
推荐阅读
- android-studio - 无法使用自定义图像在 Android Studio 上创建通知图标
- android - 如何从 mysql 数据库中检索数据到颤振应用程序?
- bash - 每次在 bash 终端中输入任何命令时,如何执行脚本?
- javascript - iOS:Polyfill NFC Web API——有可能吗?
- swift - 如何在 SwiftUI 中将颜色选择器值保存到 UserDefaults 中?
- cuba-platform - Cuba-Platform: sample-user-registration-master HSQLDB 连接错误: OutOfMemoryError: Java heap space
- pandas - 使用 Python Pycharm 安装 Flask 不专业
- python - DHT22 在 Pi Zero W 上以用户身份工作,但不以 Sudo 身份工作
- python - 在 Python 中计算同一 DataFrame 中的分类变量之间的重叠
- html - 保存和显示来自 API 的“嵌套”JSON 数据