Spec-Zone.ru › C++

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)
1) Атомарно освобождает lock, блокирует текущий поток выполнения и добавляет его в список потоков, ожидающих *this. Поток будет разблокирован, когда будет выполнено notify_all() или notify_one(), или когда истечёт заданный относительный таймаут rel_time. Он также может быть разблокирован случайным образом. При разблокировании, независимо от причины, lock повторно приобретается, и wait_for() завершается.
2) Эквивалентно return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(stop_waiting));. Этот перегруз может быть использован для игнорирования ложных пробуждений, циклически выполняя проверку, пока не будет выполнено некоторое условие (bool(stop_waiting()) == true).
3) Эквивалентно 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).

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

bool pred();​

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

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

Исключения

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

Примечания

Даже если уведомление происходит при наличии блокировки, перегрузка (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

См. также

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

© 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

Spec-Zone.ru

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