在 std::future::unwrap() 和 std::future::get() 中竞争

Race in std::future::unwrap() and std::future::get()

本文关键字:future std 竞争 get unwrap      更新时间:2023-10-16

参考 n3721 中 C++20 中即将推出的功能的后续内容"对 std::future 和相关 API 的改进">

#include <iostream>
#include <future>
#include <exception>
using std::cout;
using std::endl;
int main() {
auto prom_one = std::promise<std::future<int>>{};
auto fut_one = prom_one.get_future();
std::thread{[prom_one = std::move(prom_one)]() mutable {
auto prom_two = std::promise<int>{};
auto fut_two = prom_two.get_future();
prom_two.set_value(1);
prom_one.set_value(std::move(fut_two));
}}.detach();
auto inner_fut_unwrap = fut_one.unwrap();
auto inner_fut_get = fut_one.get();
auto th_one = std::thread{[&]() {
cout << inner_fut_unwrap.get() << endl;
}};
auto th_two = std::thread{[&]() {
cout << inner_fut_get.get() < endl;
}};
th_one.join();
th_two.join();
return 0;
}

在上面的代码中,哪个将赢得打印1的竞赛?th_one还是th_two


为了澄清我在说什么种族,这里有两个(潜在的)不雅情况,后者是真正让我感到困惑的情况。

第一种是内在未来的设置和展开;展开的未来应该作为内在未来的合适代表,即使实际的set_value没有被召唤到内在的未来。 因此,unwrap()必须返回一个代理,该代理公开线程安全接口,而不管另一端发生什么情况。

另一种情况是当来自未来的get()在其他地方已经存在代理时会发生什么,在此示例中inner_fut_unwrapinner_fut_get的代理。 在这种情况下,谁应该赢得比赛? 是解开的未来,还是通过呼唤get()外在的未来而获取的未来?

这段代码让我担心对未来和承诺是什么以及.get()做什么存在某种误解。 我们也有点奇怪,我们using namespace std;跟着很多std::.

让我们分解一下。 这是重要的部分:

#include <iostream>
#include <future>
int main() {
auto prom_one = std::promise<std::future<int>>{};
auto fut_one = prom_one.get_future();
auto inner_fut_unwrap = fut_one.unwrap();
auto inner_fut_get = fut_one.get();
// Boom! throws std::future_error()

因此,两个线程都没有"赢得"比赛,因为实际上两个线程都没有机会运行。 请注意您链接的文档,对于第 13 页的.unwrap()

删除最外层的未来,并返回指向内部未来的代理。

所以最外层的未来,fut_one,是无效的。 当你调用.get()时,它会抛出std::future_error1。 没有种族。

1:不保证。 技术上未定义的行为。