std::condition_variable_any::wait_until
template< class Lock, class Clock, class Duration >
std::cv_status
wait_until( Lock& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time );
| (1) | (с C++11) |
template< class Lock, class Clock, class Duration, class Predicate >
bool wait_until( Lock& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time,
Predicate stop_waiting );
| (2) | (с C++11) |
template< class Lock, class Clock, class Duration, class Predicate >
bool wait_until( Lock& lock,
std::stop_token stoken,
const std::chrono::time_point<Clock, Duration>& timeout_time,
Predicate stop_waiting );
| (3) | (с C++20) |
wait_until заставляет текущий поток заблокироваться до тех пор, пока не произойдет уведомление об изменении состояния переменной, пока не будет достигнуто определенное время или не произойдет ложное пробуждение, при необходимости циклически повторяя ожидание, пока не будет удовлетворено какое-либо условие (bool(stop_waiting()) == true).
lock, блокирует текущий выполняемый поток и добавляет его в список потоков, ожидающих уведомления *this. Поток будет разблокирован, когда будет выполнено notify_all() или notify_one(), или когда будет достигнута абсолютная временная метка timeout_time. Также может быть разблокирован в результате ложного пробуждения. При разблокировке, независимо от причины, lock повторно приобретается и wait_until завершается.while (!stop_waiting())
{
if (wait_until(lock, timeout_time) == std::cv_status::timeout)
return stop_waiting();
}
return true;condition_variable_any на период wait_until(), чтобы получить уведомление, если будет запрошено прекращение работы в заданном stoken состоянии; затем она эквивалентна while (!stoken.stop_requested())
{
if (stop_waiting())
return true;
if (wait_until(lock, timeout_time) == std::cv_status::timeout)
return stop_waiting();
}
return stop_waiting();Если эти функции не выполняют пост условие (lock заблокирован вызывающим потоком), вызывается std::terminate. Например, это может произойти, если повторное блокирование мьютекса выбросит исключение.
Clock должен соответствовать требованиям Clock. Программа является некорректной, если std::chrono::is_clock_v<Clock> false.(с C++20)
Параметры
| lock | - | объект типа Lock, удовлетворяющий требованиям BasicLockable, который должен быть заблокирован текущим потоком |
| stoken | - | std::stop_token для регистрации прерывания |
| timeout_time | - | объект типа std::chrono::time_point, представляющий время, когда следует остановить ожидание |
| stop_waiting | - | предикат, возвращающий false если ожидание должно быть продолжено (bool(stop_waiting()) == false). Подпись предикатной функции должна быть эквивалентна следующей:
|
Возвращаемое значение
std::cv_status::timeout если абсолютный таймаут, заданный timeout_time, был достигнут, std::cv_status::no_timeout в противном случае.false если предикат stop_waiting по-прежнему возвращает false после истечения таймаута timeout_time, в противном случае true. Если таймаут истек, вычисляет и возвращает результат stop_waiting.stop_waiting(), независимо от того, был ли достигнут таймаут или был запрошен останов.Исключения
stop_waiting.Примечания
Стандарт рекомендует использовать часы, связанные с timeout_time, для измерения времени; эти часы не обязательно должны быть монотонными. Нет гарантий относительно поведения этой функции, если часы изменяются дискретно, но существующие реализации преобразуют timeout_time из Clock в std::chrono::system_clock и делегируют вызов к POSIX pthread_cond_timedwait, чтобы ожидание учитывало изменения системных часов, но не предоставленных пользователем Clock. В любом случае, функция также может ждать дольше, чем до момента, когда timeout_time будет достигнут, из-за задержек планирования или конкуренции за ресурсы.
Даже если используемые часы являются std::chrono::steady_clock или другими монотонными часами, корректировка системных часов может вызвать ложное пробуждение.
Влияние 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 cv;
std::mutex cv_m;
std::atomic<int> i{0};
void waits(int idx)
{
std::unique_lock<std::mutex> lk(cv_m);
auto now = std::chrono::system_clock::now();
if (cv.wait_until(lk, now + 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);
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_until вызывала исключение при разблокировке/переблокировке | вызывает std::terminate |
См. также
| блокирует текущий поток до пробуждения переменной состояния (публичный член-функция) |
|
| блокирует текущий поток до пробуждения переменной состояния или после истечения указанного времени ожидания (публичный член-функция) |
|
Документация на C для cnd_timedwait |
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/condition_variable_any/wait_until