Spec-Zone.ru › C++

std::condition_variable::wait_until

template< class Clock, class Duration >
std::cv_status
    wait_until( std::unique_lock<std::mutex>& lock,
                const std::chrono::time_point<Clock, Duration>& timeout_time );
(1) (с C++11)
template< class Clock, class Duration, class Predicate >
bool wait_until( std::unique_lock<std::mutex>& lock,
                 const std::chrono::time_point<Clock, Duration>& timeout_time,
                 Predicate stop_waiting );
(2) (с C++11)

wait_until заставляет текущую нить заблокироваться до тех пор, пока переменная состояния не будет уведомлена, не будет достигнуто определённое время или не произойдёт ложное пробуждение, при необходимости циклически проверяя условие до тех пор, пока оно не будет удовлетворено (bool(stop_waiting()) == true).

1) Атомарно освобождает lock, блокирует текущую выполняющуюся нить и добавляет её в список нитей, ожидающих уведомления от *this. Нить будет разблокирована, когда будет выполнено notify_all() или notify_one(), или когда будет достигнуто абсолютное временное значение timeout_time. Она также может быть разблокирована ложно. При разблокировании, независимо от причины, lock вновь приобретается, и wait_until завершается.
2) Эквивалентно
while (!stop_waiting())
{
    if (wait_until(lock, timeout_time) == std::cv_status::timeout)
        return stop_waiting();
}
return true;
Этот перегруз может использоваться для игнорирования ложных пробуждений.

Вызов этой функции, если lock.mutex() не заблокирована текущей нитью, приводит к неопределённому поведению.

Вызов этой функции, если lock.mutex() не совпадает с мьютексом, используемым всеми другими нитями, которые в данный момент ожидают ту же самую переменную состояния, приводит к неопределённому поведению.

Если эти функции не выполняют пост-условие (lock.owns_lock()==true и lock.mutex() заблокированы вызывающей нитью), вызывается std::terminate. Например, это может произойти, если повторная блокировка мьютекса вызывает исключение.

Clock должна удовлетворять требованиям Clock. Программа некорректна, если std::chrono::is_clock_v<Clock> является false.(с C++20)

Параметры

lock - объект типа std::unique_lock<std::mutex>, который должен быть заблокирован текущей нитью
timeout_time - объект типа std::chrono::time_point, представляющий время, по истечении которого ожидание должно быть прекращено
stop_waiting - предикат, который возвращает ​false, если ожидание должно быть продолжено (bool(stop_waiting()) == false).

Подпись предикатной функции должна быть эквивалентна следующей:

bool pred();​

Возвращаемое значение

1) std::cv_status::timeout если абсолютный таймаут, указанный в timeout_time, был достигнут, std::cv_status::no_timeout в противном случае.
2) false если предикат stop_waiting по-прежнему оценивается как false после истечения таймаута timeout_time, в противном случае true. Если таймаут уже истек, вычисляет и возвращает результат stop_waiting.

Исключения

1) Любое исключение, брошенное часами, временными точками или интервалами времени во время выполнения (часы, временные точки и интервалы времени, предоставляемые стандартной библиотекой, никогда не выбрасывают исключения).
2) То же, что (1), но также может передать исключения, брошенные stop_waiting.

Примечания

Стандарт рекомендует использовать часы, связанные с timeout_time, для измерения времени; эти часы не обязаны быть монотонными часами. Нет никаких гарантий относительно поведения этой функции, если часы внезапно изменяются, но существующие реализации преобразуют timeout_time из Clock в std::chrono::system_clock и делегируют POSIX pthread_cond_timedwait, чтобы ожидание учитывало изменения системных часов, но не пользовательских Clock. В любом случае, функция также может ждать дольше, чем до достижения timeout_time, из-за задержек планирования или конкуренции за ресурсы.

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

Эффекты 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

См. также

wait
блокирует текущую нить до разбуживания переменной состояния
(публичный член-функция)
wait_for
блокирует текущую нить до разбуживания переменной состояния или после истечения заданного интервала времени
(публичный член-функция)
C documentation для cnd_timedwait

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/condition_variable/wait_until

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API