Получить статус std :: future

83

Можно ли проверить std::future, закончился или нет? Насколько я могу судить, единственный способ сделать это - позвонить wait_forс нулевой продолжительностью и проверить, есть ли статус ready, но есть ли способ лучше?

Дэвид Браун
источник
10
@CatPlusPlus Если я не ошибаюсь, validпроверяет только, есть ли у будущего общее состояние (т.е. оно возвращается trueдо тех пор, пока не getбудет вызвано в будущем).
Дэвид Браун
Итак, если getбыл вызван и вернул сохраненное значение, вы все еще хотите true? (Я не уверен, почему это может быть полезно, поскольку вы можете получить значение только один раз.)
Джеймс МакНеллис
@JamesMcNellis, возможно, я неправильно понимаю или неправильно использую фьючерсы, но я хочу знать, завершен ли поток (или что-то, что выполняет расчет) или нет. По QFuture::isFinishedсути, эквивалент Qt .
Дэвид Браун
1
Ожидание с нулевым таймаутом - вот как большинство API-интерфейсов на многих платформах справляются с такой концепцией ... Настолько, что я мог бы считать это «стандартным» подходом к концепции. Это заставляет меня немного озадачить понятие «лучший способ» ...
asveikau
16
@asveikau Я не знал, что это стандартная практика. Просто странно вызывать функцию ожидания, когда я не хочу ждать.
Дэвид Браун

Ответы:

85

Вы правы, и кроме звонка wait_untilв прошлое (что эквивалентно) нет лучшего способа.

Вы всегда можете написать небольшую оболочку, если хотите более удобный синтаксис:

template<typename R>
  bool is_ready(std::future<R> const& f)
  { return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; }

NB, если функция отложена, это никогда не вернет истину, поэтому, вероятно, лучше проверить wait_forнапрямую в том случае, когда вы можете захотеть запустить отложенную задачу синхронно по истечении определенного времени или при низкой загрузке системы.

Джонатан Уэйкли
источник
2
wait_for не изменяет будущее, поэтому параметр можно объявить как const.
Йенс Окерблом
7
Рассмотрите возможность сначала проверить valid (), чтобы избежать ошибок времени выполнения, если get уже был вызван или future не было инициализировано.
Джереми Соренсен
5
Гарантируется ли немедленный возврат wait_for (chrono :: seconds (0)), или он может передать управление потоком на пару миллисекунд в некоторых реализациях? Это было бы очень важно знать, так как пара миллисекунд - это много времени при
написании
9
@kynnysmatto, в некоторых реализациях он получает блокировку мьютекса, чтобы безопасно проверить состояние будущего, поэтому, если эта блокировка оспаривается (потому что другой поток делает состояние готовым или также проверяет готовность), он будет заблокирован, а другой поток может работать, но в хорошей реализации мьютекс никогда не должен удерживаться более чем на несколько инструкций, то есть даже на одну миллисекунду. Текущая реализация GCC вообще не использует мьютекс, но предыдущий использовал, и подготовка состояния выполняется заменой двух указателей, поэтому мьютекс блокируется очень кратковременно, пока это происходит.
Джонатан Уэйкли,
Тестирование @JonathanWakely с помощью g ++ for(int i = 0; i < 1000; i++) f.wait_for(chrono::seconds(0));занимает 43 мс времени настенных часов.
Дэниел Кинсман,
15

Для std :: future работает функция-член is_ready . А пока у реализации VC есть член _Is_ready ().

Рик Йоргасон
источник
Обратите внимание, что функция-член _Is_ready () НЕ является потокобезопасной. Он получает доступ к флагу _Ready связанного состояния без защиты. По крайней мере, это касается VS2019 16.2.
Mattias De Charleroy
10

Моя первая ставка заключалась в том, чтобы уравнять wait_forс продолжительностью 0 и проверить код результата, который может быть одним из future_status::ready, future_status::deferredили future_status::timeout.

В cppreference они утверждают, что valid() проверяет, доступен ли результат , но стандарт говорит, что valid()он вернется, trueесли *thisотносится к общему состоянию, независимо от того, готово ли это состояние или нет.

Давид Родригес - дрибеас
источник
7
cppreference теперь обновлен и в нем указано «проверяет, есть ли у будущего общее состояние». (Не уверен, хотите ли вы удалить второй абзац или отредактировать его, поэтому я не буду его изменять).
Default