std::condition_variable::wait_for
template< class Rep, class Period >
std::cv_status wait_for( std::unique_lock<std::mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time );
| (1) | (с C++11) |
template< class Rep, class Period, class Predicate >
bool wait_for( std::unique_lock<std::mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate stop_waiting );
| (2) | (с C++11) |
lock, блокирует текущий поток выполнения и добавляет его в список потоков, ожидающих *this. Поток будет разблокирован, когда будет выполнено notify_all() или notify_one(), или когда истечёт заданный относительный таймаут rel_time. Он также может быть разблокирован случайным образом. При разблокировании, независимо от причины, lock повторно приобретается, и выполнение wait_for() завершается.return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(stop_waiting));. Этот перегруз может использоваться для игнорирования ложных пробуждений, циклически проверяя, пока не будет выполнено некоторое условие (bool(stop_waiting()) == true).Стандарт рекомендует использовать стабильный таймер для измерения продолжительности ожидания. Данная функция может блокироваться дольше, чем timeout_duration из-за задержек планирования или конкуренции за ресурсы.
Вызов этой функции, если lock.mutex() не заблокирован текущим потоком, приводит к неопределённому поведению.
Вызов этой функции, если lock.mutex() не является тем же мьютексом, что и тот, который используется всеми другими потоками, которые в данный момент ожидают того же условия, приводит к неопределённому поведению.
Если эти функции не выполняют пост-условие (lock.owns_lock()==true и lock.mutex() заблокированы вызывающим потоком), вызывается std::terminate. Например, это может произойти, если повторное блокирование мьютекса вызывает исключение.
Параметры
| lock | - | объект типа std::unique_lock<std::mutex>, который должен быть заблокирован текущим потоком |
| rel_time | - | объект типа std::chrono::duration, представляющий максимальное время ожидания. Обратите внимание, что rel_time должен быть достаточно малым, чтобы избежать переполнения при добавлении к std::chrono::steady_clock::now(). |
| stop_waiting | - | предикат, возвращающий false если ожидание должно продолжаться (bool(stop_waiting()) == false). Подпись функции-предиката должна быть эквивалентна следующей:
|
Возвращаемое значение
std::cv_status::timeout если истек относительный таймаут, заданный rel_time, в противном случае std::cv_status::no_timeout.false если предикат stop_waiting по-прежнему возвращает false после истечения таймаута rel_time, в противном случае true.Исключения
stop_waiting.Примечания
Даже если уведомление выполняется под блокировкой, перегрузка (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 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 |
См. также
| блокирует текущий поток, пока условие не будет выполнено (публичный член-функция) |
|
| блокирует текущий поток, пока условие не будет выполнено или не будет достигнут указанный момент времени (публичный член-функция) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/condition_variable/wait_for