std::condition_variable
当 std::condition_variable 对象的某个 wait 函数被调用的时候,它使用 std::unique_lock(通过 std::mutex) 来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的 std::condition_variable 对象上调用了 notification 函数来唤醒当前线程。
std::condition_variable 对象通常使用 std::unique_lockstd::mutex 来等待,如果需要使用另外的 lockable 类型,可以使用 std::condition_variable_any 类,本文后面会讲到 std::condition_variable_any 的用法。
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 33 34 35 36 37 38 39 40
| #include <iostream> #include <thread> #include <mutex> #include <condition_variable>
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) cv.wait(lck); std::cout << "thread " << id << '\n'; }
void go() { std::unique_lock <std::mutex> lck(mtx); ready = true; cv.notify_all(); }
int main() { std::thread threads[10]; 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 构造函数
std::condition_variable 的拷贝构造函数被禁用,只提供了默认构造函数
std::condition_variable::wait
1.void wait(unique_lock& lck);
2.template void wait (unique_lock& lck, Predicate pred);
td::condition_variable 提供了两种 wait() 函数。
第一种情况,当前线程调用 wait() 后将被阻塞(此时当前线程应该获得了锁(mutex),不妨设获得锁 lck),直到另外某个线程调用 notify_* 唤醒了当前线程。
在线程被阻塞时,该函数会自动调用 lck.unlock() 释放锁,使得其他被阻塞在锁竞争上的线程得以继续执行。另外,一旦当前线程获得通知(notified,通常是另外某个线程调用 notify_* 唤醒了当前线程),wait() 函数也是自动调用 lck.lock(),使得 lck 的状态和 wait 函数被调用时相同。
在第二种情况下(即设置了 Predicate),只有当 pred 条件为 false 时调用 wait() 才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred 为 true 时才会被解除阻塞。 类似while (!pred()) wait(lck);
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 33 34 35 36 37 38 39 40 41 42
| #include <iostream> #include <thread> #include <mutex> #include <condition_variable>
std::mutex mtx; std::condition_variable cv;
int cargo = 0; bool shipment_available() { return cargo != 0; }
void consume(int n) { for (int i = 0; i < n; ++i) { std::unique_lock <std::mutex> lck(mtx); cv.wait(lck, shipment_available); std::cout << cargo << '\n'; cargo = 0; } }
int main() { std::thread consumer_thread(consume, 10);
for (int i = 0; i < 10; ++i) { while (shipment_available()) std::this_thread::yield(); std::unique_lock <std::mutex> lck(mtx); cargo = i + 1; cv.notify_one(); }
consumer_thread.join();
return 0; }
|
std::condition_variable::wait_for
与std::condition_variable::wait类似
std::condition_variable::wait_until
与std::condition_variable::wait_until类似
std::condition_variable::notify_one
唤醒某个等待(wait)线程。如果当前没有等待线程,则该函数什么也不做,如果同时存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。
std::condition_variable::notify_all
唤醒所有的等待(wait)线程。如果当前没有等待线程,则该函数什么也不做。
std::condition_variable_any
与 std::condition_variable 类似,只不过 std::condition_variable_any 的 wait 函数可以接受任何 lockable 参数,而 std::condition_variable 只能接受 std::unique_lockstd::mutex 类型的参数,除此以外,和 std::condition_variable 几乎完全一样。
std::cv_status枚举类
cv_status::no_timeout: wait_for 或者 wait_until 没有超时,即在规定的时间段内线程收到了通知。
cv_status::timeout: wait_for 或者 wait_until 超时。
std::notify_all_at_thread_exit
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 33 34 35 36
| #include <iostream> #include <thread> #include <mutex> #include <condition_variable>
std::mutex mtx; std::condition_variable cv; bool ready = false;
void print_id (int id) { std::unique_lock<std::mutex> lck(mtx); while (!ready) cv.wait(lck); std::cout << "thread " << id << '\n'; }
void go() { std::unique_lock<std::mutex> lck(mtx); std::notify_all_at_thread_exit(cv,std::move(lck)); ready = true; }
int main () { std::thread threads[10]; for (int i=0; i<10; ++i) threads[i] = std::thread(print_id,i); std::cout << "10 threads ready to race...\n";
std::thread(go).detach();
for (auto& th : threads) th.join();
return 0; }
|
原文链接: https://kettycode.github.io/2024/02/06/cpp/并发编程/condition_variable/
版权声明: 转载请注明出处.