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 pred );
(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 pred );
(3) (начиная с C++20)

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

1) Эквивалентно return wait_until(lock, std::chrono::steady_clock::now() + rel_time);.
2,3) Ожидание наступления определённого условия; может использоваться для игнорирования ложных пробуждений.
2) Эквивалентно return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred));.
3) Регистрирует *this на время этого вызова, чтобы получить уведомление при отправке запроса на остановку для связанного состояния остановки stoken; затем эквивалентно return wait_until(lock, std::move(stoken),std::chrono::steady_clock::now() + rel_time, std::move(pred));.

Сразу после возврата wait_for поток, вызвавший функцию, блокирует lock. Если это постусловие не может быть выполнено[1], вызывается std::terminate.

  1. Это может произойти, если при повторной блокировке мьютекса выбрасывается исключение.

Параметры

lock - блокировка, которая должна быть захвачена потоком, вызвавшим функцию
stoken - токен остановки, для которого регистрируется прерывание
rel_time - максимальное время ожидания
pred - предикат для проверки возможности завершения ожидания
Требования к типам
-Lock должен соответствовать требованиям BasicLockable.
-Predicate должен соответствовать требованиям FunctionObject.
-pred() должно быть допустимым выражением, а его тип и категория значения должны соответствовать требованиям BooleanTestable.

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

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

Исключения

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

Примечания

Даже если уведомление было отправлено при захваченной блокировке, перегрузка (1) не даёт никаких гарантий относительно состояния связанного предиката при возврате из-за тайм-аута.

Эффекты 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_any 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_until
блокирует текущий поток до пробуждения условной переменной или наступления указанного момента времени
(открытая функция-член)

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

Spec-Zone.ru

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