поведение std::async(std::launch::deferred) + std::future::then

Идея отложенного будущего (достигаемого только вызовом std::async с флагом std::launch::deferred) заключается в том, что обратный вызов вызывается только тогда, когда кто-то пытается подождать или получить футуристическое значение или исключение будущего. к тому времени обратный вызов не выполняется.

Что произойдет, если я присоединю продолжение к отложенному будущему с помощью std::future::then? отложенное будущее теряется (then делает будущее недействительным) и вместо него возвращается новое будущее.

В этом случае, согласно стандарту, что должно произойти? Является ли новое будущее отложенным будущим? это просто тупик? этот вопрос не рассматривается в последней документации.


person David Haim    schedule 21.07.2018    source источник
comment
Старый проект спецификации (open-std.org /jtc1/sc22/wg21/docs/papers/2013/n3721.pdf ) упоминает: Если у родителя есть политика launch::deferred, а у продолжения нет указанной политики запуска или планировщика, затем родитель заполняется немедленным вызовом .wait(), а политика антецедента — launch::deferred   -  person Matthias247    schedule 22.07.2018
comment
Однако я больше не могу найти это в более новой версии open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0159r0.html   -  person Matthias247    schedule 22.07.2018


Ответы (1)


На мой взгляд, это ошибка в ТС. Или, по крайней мере, незадокументированная ловушка.

Вот текст из ТС:

2.3 [futures.unique_future]/6-10

template <class F>
see below then(F&& func);

Требует:

INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) shall be a valid expression.

Последствия:

Функция создает общее состояние, связанное с возвращаемым будущим объектом. Кроме того,

Когда общее состояние объекта готово, продолжение INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this)) вызывается в неуказанном потоке выполнения, при этом вызов DECAY_COPY() оценивается в потоке, который тогда вызвал.

Любое значение, возвращенное из продолжения, сохраняется как результат в общем состоянии результирующего будущего. Любое исключение, распространяющееся при выполнении продолжения, сохраняется как исключительный результат в общем состоянии результирующего будущего.

Возвращает:

Когда result_of_t<decay_t<F>(future<R>)> равно future<R2>, для некоторого типа R2 функция возвращает future<R2>. В противном случае функция возвращает future<result_of_t<decay_t<F>(future<R>)>>. [Примечание: приведенное выше правило называется неявной разверткой. Без этого правила возвращаемый тип вызываемого объекта, возвращающего future<R>, был бы future<future<R>>. Это правило позволяет избежать таких вложенных будущих объектов. Тип f2 ниже — это future<int>, а не future<future<int>>:

[ Пример:

future<int> f1 = g();
future<int> f2 = f1.then([](future<int> f) {
                    future<int> f3 = h();
                    return f3;
                 });

— конец примера]

— примечание в конце]

Постусловия:

valid() == false на исходное будущее. valid() == true на будущее вернулся из того времени. [Примечание: в случае неявной развертки действительность будущего, возвращаемого из thenfunc, не может быть установлена ​​до завершения продолжения. Если это недопустимо, результирующее будущее становится готовым с исключением типа std::future_error с условием ошибки std::future_errc::broken_promise. — примечание в конце]

Нет особого случая для отложенной будущей задачи. Если эта отложенная будущая задача не готова до вызова .then, у нее нет возможности стать готовой, поэтому устаревшая копия func не может быть вызвана.

Текст для shared_future аналогичен; там вы все равно можете заставить shared_future стать готовым после вызова .then однако.

Если это предназначено; что .then в неготовом отложенном уникальном будущем приведет к возвращаемому значению future, которое никогда не может быть готово - это должно быть явно указано в TS/стандарте. Если это не предусмотрено, стандартный текст необходимо изменить.

Обратите внимание, что эти изменения не отображаются в N4762. проект стандарта, опубликованный в 2018 году.

Я не уверен, как стандарт должен исправить это; семантика .then приемлема для shared_future, но не для future, и другая семантика была бы неожиданной.

person Yakk - Adam Nevraumont    schedule 29.08.2018