Гонка в std :: future :: unwrap () и std :: future :: get ()

Продолжение со ссылкой на предстоящую функцию в C ++ 20 от n3721 «Улучшения в 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_unwrap это прокси для inner_fut_get, В такой ситуации, кто должен выиграть гонку? Развернутое будущее или будущее, извлеченное с помощью звонка get() на внешнее будущее?

2

Решение

Этот код заставляет меня беспокоиться о том, что существует какое-то недопонимание того, что такое будущее и какие обещания, и что .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()

Таким образом, ни один из потоков не «выигрывает» гонку, поскольку ни один из потоков на самом деле не имеет шансов на запуск. Примечание из документа, который вы связали, для .unwrap()на стр. 13:

Удаляет самое внешнее будущее и возвращает прокси во внутреннее будущее.

Итак, самое внешнее будущее, fut_one, не является действительным. Когда вы звоните .get()кидает std::future_error1. Там нет расы.

1: Не гарантировано. Технически неопределенное поведение.

1

Другие решения

Других решений пока нет …