代码
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::condition_variable cv_02;
std::mutex cv_m_02; // This mutex is used for three purposes:
// 1) to synchronize accesses to i
// 2) to synchronize accesses to std::cerr
// 3) for the condition variable cv
int i = 0;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m_02); // 因lock_guard不提供lock()和unlock()方法,在notify端调用了notify_all()或notify_one()时wait()/等待线程将会对条件进行测试,测试时会调用lock()和unlock(),此处不能使用lock_guard
// cv_02.wait(lk, [] {return i == 1; });
/*
* 1. 获得锁: std::unique_lock<std::mutex> lk(cv_m_02),获得锁(构造unique_lock时调用lock()方法)的目的是用于对条件变量(如本例中的i)进行测试
* 2. wait()将当前线程放入等待队列,并对lk(即cv_m_02)进行解锁(即调用unlock()),解锁目的是允许其他线程获得锁并对测试条件进行改变,并等待其他线程调用notify_one()/notify_all()唤醒
* 3. 首次调用wait()时将对条件变量(如本例中的i)进行测试
* 4. 当其他线程调用notify_one()/notify_all()时,wait()将重新获得锁并对条件(本例中的i是否为1)进行测,测试失败时再次释放锁(允许其他线程获得锁并对测试条件进行改变)
* 5. 当wait()测试条件满足(如本例中的i=1),被唤醒后,重新获得锁(即调用lock()方法),当锁(本例的lk)所在作用域(如waits方法运行完)外时将被自动解锁(即lk虚构方法自动调用unlock()进行解锁)
*/
cv_02.wait(lk, [] {
if (i == 1) { // 条件测试成功,唤醒
std::cerr << "thread-" << std::this_thread::get_id() << " wakeup... \n";
return true;
}
else { // 条件测试失败,继续等待
std::cerr << "thread-" << std::this_thread::get_id() << " condition is false, Waiting notify continue... \n";
return false;
}
});
std::cerr << "thread-" << std::this_thread::get_id() << " ...finished waiting. i == 1\n";
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m_02);
std::cerr << "Notifying...\n";
} // 作用域(注意一对大括号)外时,lk被释放(即cv_m_02被释放)外,其他线程可以获得锁(即本例中的cv_m_02)
cv_02.notify_all(); // 唤醒所有等待线程,条件变量为i=0,等待线程测试条件将失败,继续等待
//cv_02.notify_one(); // 唤醒一个等待线程,条件变量为i=0,等待线程测试条件将失败,继续等待
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m_02);
i = 1;
std::cerr << "Notifying again...\n";
} // 作用域(注意一对大括号)外时,lk被释放(即cv_m_02被释放)外,其他线程可以获得锁(即本例中的cv_m_02)
cv_02.notify_all(); // 唤醒所有等待线程,条件变量为i=1,所有等待线程将被唤醒
}
void test02()
{
std::thread t1(waits), t2(waits), t3(waits), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
}
int main()
{
test02();
}
运行结果
thread-23988 condition is false, Waiting notify containue...
thread-4264 condition is false, Waiting notify containue...
thread-4812 condition is false, Waiting notify containue...
Notifying...
thread-23988 condition is false, Waiting notify containue...
Notifying again...
thread-23988 wakeup...
thread-23988 ...finished waiting. i == 1
thread-4812 wakeup...
thread-4812 ...finished waiting. i == 1
thread-4264 wakeup...
thread-4264 ...finished waiting. i == 1