std::condition_variable_any::wait_for
template< class Lock, class Rep, class Period >
std::cv_status wait_for( Lock& lock,
const std::chrono::duration<Rep, Period>& rel_time );
|
(1) | (с C++11) |
template< class Lock, class Rep, class Period, class Predicate >
bool wait_for( Lock& lock,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate stop_waiting );
|
(2) | (с C++11) |
template< class Lock, class Rep, class Period, class Predicate >
bool wait_for( Lock& lock,
std::stop_token stoken,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate stop_waiting );
|
(3) | (с C++20) |
lock, блокирует текущий поток выполнения и добавляет его в список потоков, ожидающих *this. Поток будет разблокирован, когда будет выполнено notify_all() или notify_one(), или когда истечёт заданный относительный таймаут rel_time. Он также может быть разблокирован случайным образом. При разблокировании, независимо от причины, lock повторно приобретается, и wait_for() завершается.
return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(stop_waiting));. Этот перегруз может быть использован для игнорирования ложных пробуждений, циклически выполняя проверку, пока не будет выполнено некоторое условие (bool(stop_waiting()) == true).
return wait_until(lock, std::move(stoken), std::chrono::steady_clock::now() + rel_time, std::move(stop_waiting));.
Стандарт рекомендует использовать стабильные часы для измерения длительности. Эта функция может блокироваться дольше, чем timeout_duration из-за задержек планирования или конкуренции за ресурсы.
Если эти функции не выполнят пост условие (lock заблокирован вызывающим потоком), вызывается std::terminate. Например, это может произойти, если повторная блокировка мьютекса сгенерирует исключение.
Параметры
| lock | - | объект типа Lock, удовлетворяющий требованиям BasicLockable, который должен быть заблокирован текущим потоком |
| stoken | - | std::stop_token для регистрации прерывания |
| rel_time | - | объект типа std::chrono::duration, представляющий максимальное время ожидания. Обратите внимание, что rel_time должен быть достаточно малым, чтобы не произойти переполнение при сложении с std::chrono::steady_clock::now(). |
| stop_waiting | - | предикат, возвращающий false если ожидание должно быть продолжено (bool(stop_waiting()) == false).Подпись предикатной функции должна быть эквивалентна следующей:
|
Возвращаемое значение
std::cv_status::timeout если истек относительный таймаут, заданный rel_time, std::cv_status::no_timeout в противном случае.
false если предикат stop_waiting по-прежнему возвращает false после истечения таймаута rel_time, в противном случае true.
stop_waiting(), независимо от того, истек ли таймаут или было запрошено завершение.
Исключения
stop_waiting.
Примечания
Даже если уведомление происходит при наличии блокировки, перегрузка (1) не даёт никаких гарантий о состоянии связанного предиката при возвращении из-за истечения таймаута.
Эффекты notify_one()/notify_all() и каждой из трёх атомарных частей wait()/wait_for()/wait_until() (разблокировка+ожидание, пробуждение и блокировка) происходят в одной общей последовательности, которая может быть рассмотрена как порядок модификации атомной переменной: порядок специфичен для данной переменной условия. Это делает невозможным, например, задержку notify_one() и разблокировку потока, который начал ожидание сразу после вызова notify_one().
Пример
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <thread>
using namespace std::chrono_literals;
std::condition_variable_any cv;
std::mutex cv_m;
int i;
void waits(int idx)
{
std::unique_lock<std::mutex> lk(cv_m);
if (cv.wait_for(lk, idx*100ms, []{ return i == 1; }))
std::cerr << "Thread " << idx << " finished waiting. i == " << i << '\n';
else
std::cerr << "Thread " << idx << " timed out. i == " << i << '\n';
}
void signals()
{
std::this_thread::sleep_for(120ms);
std::cerr << "Notifying...\n";
cv.notify_all();
std::this_thread::sleep_for(100ms);
{
std::lock_guard<std::mutex> lk(cv_m);
i = 1;
}
std::cerr << "Notifying again...\n";
cv.notify_all();
}
int main()
{
std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
}Вывод:
Thread 1 timed out. i == 0 Notifying... Thread 2 timed out. i == 0 Notifying again... Thread 3 finished waiting. i == 1
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применимо к | Поведение при публикации | Корректное поведение |
|---|---|---|---|
| LWG 2093 | C++11 | Исключения, связанные с таймаутом, отсутствовали в спецификации | Указано |
| LWG 2135 | C++11 |
wait_for генерировало исключение при разблокировании/повторной блокировке с ошибкой |
Вызывается std::terminate |
См. также
| блокирует текущий поток до пробуждения условия (публичный член-функция) |
|
| блокирует текущий поток до пробуждения условия или достижения указанной временной метки (публичный член-функция) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/condition_variable_any/wait_for