最近看了下c++11的线程。看了不少博客,这里会引用到CSDN里Nine-days博客里的demo。
notify_one:唤醒等待线程中的一个。
notify_all:唤醒所有等待的线程。
wait:等待。需要其它的接口来唤醒。
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
//demo std::mutex mtx_syn; std::condition_variable cv_syn; std::condition_variable cv_syn_1; bool ready = false;
//线程A void threadA(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) { cv_syn.wait(lck); } // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_one(); // 唤醒等待线程中的一个 cv_syn.wait(lck); // 等待 } }
// 线程B void threadB(int id) { while (1) { //新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞 std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) { cv_syn.wait(lck); } // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_one(); // 唤醒等待线程中的一个 cv_syn.wait(lck); } } // 线程C void threadC(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) cv_syn.wait(lck); // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_one(); // 唤醒等待线程中的一个线程 cv_syn.wait(lck); } } void go() { std::unique_lock<std::mutex> lck(mtx_syn); ready = true; cv_syn.notify_one(); // 唤醒等待线程中的一个线程 }
int main() { //线程同步 std::thread threads[5]; threads[0] = std::thread(threadA, 0); threads[1] = std::thread(threadB, 1); threads[2] = std::thread(threadC, 2); std::cout << "3 threads ready to race...\n"; go(); // go! for (auto& th : threads) th.join(); }
3 threads ready to race... thread 0 thread 1 thread 2 thread 0 thread 1 thread 2 thread 0 thread 1 thread 2 thread 0 thread 1 thread 2
通过main函数,知道实例化了3个线程。线程A,B,C在创建后被阻塞。go函数实现对线程的唤醒。
执行后发现go函数通过cv_syn.notify_one();唤醒的线程是A。
A线程,执行cv_syn.notify_one();唤醒的线程是B。
B线程,执行cv_syn.notify_one();唤醒的线程是C。
C线程,执行cv_syn.notify_one();唤醒的线程是A。
这里有一个没弄懂的地方。通过cv_syn.notify_one()唤醒,是依次唤醒,而不是随机。
#include <iostream> #include <thread> #include <condition_variable> #include <mutex> //demo std::mutex mtx_syn; std::condition_variable cv_syn; std::condition_variable cv_syn_1; bool ready = false; //线程A void threadA(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) { cv_syn.wait(lck); } // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_all(); // 唤醒所有等待线程:B和C,B和C将会竞争锁 cv_syn.wait(lck); } } // 线程B void threadB(int id) { while (1) { //新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞 std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) { cv_syn.wait(lck); } // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_all(); // 唤醒所有等待线程:A和C,它们将会竞争锁 cv_syn.wait(lck); } } // 线程C void threadC(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) cv_syn.wait(lck); // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_all(); // 唤醒所有等待线程:A和B,它们将会竞争锁 cv_syn.wait(lck); } } void go() { std::unique_lock<std::mutex> lck(mtx_syn); ready = true; cv_syn.notify_one(); // 唤醒等待线程中的一个线程 } int main() { //线程同步 std::thread threads[5]; threads[0] = std::thread(threadA, 0); threads[1] = std::thread(threadB, 1); threads[2] = std::thread(threadC, 2); std::cout << "3 threads ready to race...\n"; go(); // go! for (auto& th : threads) th.join(); }
3 threads ready to race... thread 0 thread 1 thread 2 thread 0 thread 1 thread 2 thread 0 thread 2 thread 0 thread 2 thread 0 thread 1 thread 0
通过输出知道,cv_syn.notify_all()唤醒了等待的所有线程,但是这些被唤醒的线程需要去竞争锁,只有获取到锁,才可以进行输出。
而cv_syn.notify_one()则不是这样,它没有竞争。
这样go里使用notify_one就不合适。应该改为notify_all. 三个线程就会对锁进行竞争。
输出如下
3 threads ready to race... thread 2 thread 1 thread 2 thread 1 thread 2 thread 1 thread 2 thread 0 thread 2 thread 0 thread 2 thread 0 thread 2 thread 0