[TOC] # std::condition_variable ## std::condition_variable::wait() 签名 ``` void wait (unique_lock<mutex>& lck) void wait (unique_lock<mutex>& lck, Predicate pred) ``` - `wait(lck) ` 调用 wait() 后将被阻塞(此时当前线程应该获得了锁(mutex),不妨设获得锁 lck),直到另外某个线程调用 notify_* 唤醒了当前线程。 在线程被阻塞时,该函数会自动调用 lck.unlock() 释放锁,使得其他被阻塞在锁竞争上的线程得以继续执行。另外,一旦当前线程获得通知(notified,通常是另外某个线程调用 notify_* 唤醒了当前线程),wait()函数也是自动调用 lck.lock(),使得lck的状态和 wait 函数被调用时相同。 - `wait(lck,pred)` 只有当 pred 条件为false 时调用 wait() 才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred 为 true 时才会被解除阻塞。相当于:` while (!pred()) wait(lck); ` ## std::condition_variable::wait_for() ``` template <class period> cv_status wait_for (unique_lock<mutex>& lck,const chrono::duration<rep,period>& rel_time); template <class predicate> bool wait_for (unique_lock<mutex>& lck,const chrono::duration<rep,period>& rel_time, Predicate pred); ``` - `wait_for(lck,rel_time)` wait_for可以指定一个时间段,在当前线程收到通知或者指定的时间 rel_time 超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其他线程的通知,wait_for返回,剩下的处理步骤和 wait()类似。 - `wait_for(lck,rel_time,pred)` 只有当 pred条件为false时调用 wait()才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred为 true时才会被解除阻塞,等价于 `return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred));` 例子: ``` std::condition_variable cv; int value; void do_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(do_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::cout.flush(); } std::cout << "You entered: " << value << '\n'; th.join(); return 0; } ``` ## std::condition_variable::wait_until ``` template <class duration> cv_status wait_until (unique_lock<mutex>& lck,const chrono::time_point<clock,duration>& abs_time); template <class predicate> bool wait_until (unique_lock<mutex>& lck,const chrono::time_point<clock,duration>& abs_time,Predicate pred); ``` - `wait_until(lck,abs_time)` wait_until可以指定一个时间点,在当前线程收到通知或者指定的时间点 abs_time超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其他线程的通知,wait_until返回,剩下的处理步骤和 wait_until() 类似。 - `wait_until(lck,abs_time,pred)` 只有当 pred条件为 false时调用 wait()才会阻塞当前线程,并且在收到其他线程的通知后只有当pred为 true时才会被解除阻塞,相当于如下代码: ``` while (!pred()) if ( wait_until(lck,abs_time) == cv_status::timeout) return pred(); return true; ``` ## std::condition_variable::notify_one() 唤醒某个等待(wait)线程。如果当前没有等待线程,则该函数什么也不做,如果同时存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。 ## std::condition_variable::notify_all() 唤醒所有的等待(wait)线程。如果当前没有等待线程,则该函数什么也不做。 例子: ``` std::mutex mtx; // 全局互斥锁. std::condition_variable cv; // 全局条件变量. bool ready = false; // 全局标志位. void do_print_id(int id) { std::unique_lock <std::mutex> lck(mtx); while (!ready) // 如果标志位不为 true, 则等待... cv.wait(lck); // 当前线程被阻塞, 当全局标志位变为 true 之后, // 线程被唤醒, 继续往下执行打印线程编号id. std::cout << "thread " << id << '\n'; } void go() { std::unique_lock <std::mutex> lck(mtx); ready = true; // 设置全局标志位为 true. cv.notify_all(); // 唤醒所有线程. } int main() { std::thread threads[10]; // spawn 10 threads: for (int i = 0; i < 10; ++i) threads[i] = std::thread(do_print_id, i); std::cout << "10 threads ready to race...\n"; go(); for (auto & th:threads) th.join(); return 0; } ``` # std::condition_variable_any 与 std::condition_variable类似,只不过std::condition_variable_any的 wait 函数可以接受任何 lockable参数,而 std::condition_variable只能接受 std::unique_lock类型的参数,除此以外,和std::condition_variable几乎完全一样。 # unique_lock和lock_guard - unique_lock提供unlock和lock,但是lock_guard不提供,只有在虚构时候才会解锁,如下: ``` { lock_guard lock(ml); doSomthing(); }//域结束,lock_guard对象便虚构 ``` - 都不能复制,lock_guard不能移动,但是unique_lock可以!