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>& abs_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>& abs_time,
                 Predicate pred );
(2) (начиная с C++11)

wait_until блокирует текущий поток до тех пор, пока переменная условия не будет оповещена, не наступит заданный момент времени или не произойдёт ложное пробуждение. pred можно передать для обнаружения ложных пробуждений.

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

Сразу после возврата wait_until, lock.owns_lock() находится в состоянии true, а lock.mutex() заблокирован вызывающим потоком. Если эти постусловия не могут быть выполнены[1], вызывается std::terminate.

Если выполняется любое из следующих условий, поведение не определено:

  • lock.owns_lock() имеет значение false.
  • lock.mutex() не заблокирован вызывающим потоком.
  • Если другие потоки также ожидают на *this, lock.mutex() отличается от мьютекса, разблокируемого функциями ожидания (wait, wait_for и wait_until), вызываемыми этими потоками для *this.
  1. Это может произойти, если повторная блокировка мьютекса генерирует исключение.

Параметры

lock - мьютекс, который должен быть заблокирован вызывающим потоком
abs_time - момент времени, по наступлении которого ожидание прекращается
pred - предикат для проверки того, может ли ожидание быть завершено
Требования к типам
-Predicate должен удовлетворять требованиям FunctionObject.
-pred() должно быть допустимым выражением, а его тип и категория значения должны удовлетворять требованиям BooleanTestable.

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

1) std::cv_status::timeout, если наступил abs_time, в противном случае std::cv_status::no_timeout.
2) Последний результат pred() перед возвратом управления вызывающему коду.

Исключения

1) Исключения, связанные с истечением времени ожидания.
2) Исключения, связанные с истечением времени ожидания, а также любые исключения, выброшенные pred.

Примечания

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

Даже если используемые часы — это std::chrono::steady_clock или другие монотонные часы, изменение системных часов может вызвать ложное пробуждение.

Эффекты notify_one()/notify_all() и каждой из трёх атомарных частей wait()/wait_for()/wait_until() (разблокировка и ожидание, пробуждение и блокировка) происходят в едином общем порядке, который можно рассматривать как порядок модификации атомарной переменной: этот порядок относится только к данной переменной условия. Благодаря этому notify_one(), например, не может быть задержано и разблокировать поток, начавший ожидание сразу после вызова notify_one().

Пример

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <thread>

std::condition_variable cv;
std::mutex cv_m; // This mutex is used for three purposes:
                 // 1) to synchronize accesses to i
                 // 2) to synchronize accesses to std::cerr
                 // 3) for the condition variable cv
int i = 0;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cerr << "Waiting... \n";
    cv.wait(lk, []{ return i == 1; });
    std::cerr << "...finished waiting. i == 1\n";
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::cerr << "Notifying...\n";
    }
    cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}

int main()
{
    std::thread t1(waits), t2(waits), t3(waits), t4(signals);
    t1.join(); 
    t2.join(); 
    t3.join();
    t4.join();
}

Возможный вывод:

Waiting...
Waiting...
Waiting...
Notifying...
Notifying again...
...finished waiting. i == 1
...finished waiting. i == 1
...finished waiting. i == 1

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроспективно к ранее опубликованным стандартам C++.

DR Применён к Опубликованное поведение Исправленное поведение
LWG 2093 C++11 в спецификации отсутствовали исключения, связанные с истечением времени ожидания упоминает эти исключения
LWG 2114
(P2167R3)
C++11 требование преобразуемости в bool было слишком слабым, чтобы отражать ожидания реализаций требования усилены
LWG 2135 C++11 поведение было неясным, если lock.lock() выбрасывает исключение в этом случае вызывается std::terminate

См. также

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

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

Spec-Zone.ru

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