public member function
<condition_variable>

std::condition_variable::wait_for

无条件 (1)
template <class Rep, class Period>  cv_status wait_for (unique_lock<mutex>& lck,                      const chrono::duration<Rep,Period>& rel_time);
谓词 (2)
template <class Rep, class Period, class Predicate>       bool wait_for (unique_lock<mutex>& lck,                      const chrono::duration<Rep,Period>& rel_time, Predicate pred);
等待超时或直到被通知
当前线程的执行(该线程应已锁定 lck互斥锁)在 rel_time 时间内被阻塞,或者直到被通知(如果后者先发生)。

在线程阻塞时,该函数会自动调用 lck.unlock(),允许其他已锁定的线程继续执行。

一旦被通知rel_time 时间过去,该函数将解除阻塞并调用 lck.lock(),使 lck 处于调用函数时的相同状态。然后函数返回(请注意,最后这个互斥锁锁定操作可能会在返回前再次阻塞线程)。

通常,该函数是被另一个线程调用成员函数 notify_onenotify_all 来唤醒的。但某些实现可能会产生虚假唤醒,而无需调用这些函数中的任何一个。因此,该函数的使用者应确保其恢复条件已满足。

如果指定了 pred (2),则仅当 pred 返回 false 时,函数才会阻塞,并且只有当 pred 变为 true 时,通知才能解除线程的阻塞(这在对抗虚假唤醒时特别有用)。它的行为相当于以下实现:
1
return wait_until (lck, chrono::steady_clock::now() + rel_time, std::move(pred));

参数

lck
一个 unique_lock 对象,其互斥量对象当前被该线程锁定。
所有对此对象的wait成员函数的并发调用都必须使用相同的底层互斥量对象(通过 lck.mutex() 返回)。
rel_time
线程等待被通知的最长可能时间间隔。
duration 是一个表示特定相对时间的对象。
pred
一个可调用对象或函数,它不接受任何参数,并返回一个可以被评估为 bool 的值。
此函数会反复调用 pred,直到其求值为 true

返回值

无条件版本 (1) 返回 cv_status::timeout 表示函数因 rel_time 超时而返回,否则返回 cv_status::no_timeout
谓词版本 (2) 返回 pred(),而不管超时是否被触发(尽管它只有在被触发时才能为 false)。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// condition_variable::wait_for example
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <chrono>             // std::chrono::seconds
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable, std::cv_status

std::condition_variable cv;

int value;

void read_value() {
  std::cin >> value;
  cv.notify_one();
}

int main ()
{
  std::cout << "Please, enter an integer (I'll be printing dots): \n";
  std::thread th (read_value);

  std::mutex mtx;
  std::unique_lock<std::mutex> lck(mtx);
  while (cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout) {
    std::cout << '.' << std::endl;
  }
  std::cout << "You entered: " << value << '\n';

  th.join();

  return 0;
}

可能的输出

Please, enter an integer (I'll be priniting dots):
.
.
7
You entered: 7


数据竞争

该函数执行三个原子操作:
  • lck 的初始解锁和同时进入等待状态。
  • 解除等待状态。
  • 在返回前锁定 lck
该对象上的原子操作按照单一的全局顺序进行排序,该函数中的三个原子操作的发生顺序与上述顺序相同。

异常安全

如果任何参数的值对此函数无效(例如,如果 lck互斥锁对象未被调用线程锁定),则会导致未定义行为

否则,如果抛出异常,则 condition_variable 对象和参数都处于有效状态(基本保证)。

在失败的情况下,它可能抛出 system_error(将来自相应 lockunlock 调用的任何错误条件传递)。

谓词版本 (2) 也可能抛出由 pred 抛出的任何异常。

发生异常时,在退出函数作用域之前,会尝试恢复 lck 的状态(通过调用 lck.lock())。
如果与 rel_time 相关的操作抛出异常,它也可能抛出异常(请注意,<chrono> 提供的 duration 类型(如 seconds)的操作永远不会抛出异常)。

谓词版本 (2) 也可能抛出由 pred 抛出的异常。

如果函数在某个时刻未能恢复锁定并返回(例如,如果尝试锁定或解锁时抛出异常),则会调用 std::terminate

另见