条件变量和互斥锁在多线程同步过程中经常被使用,以下测试程序测试其使用。
目录
1.测试程序1
2.测试程序2
3.运行结果思考
1.测试程序1
#include <mutex>
#include <deque>
#include <iostream>
#include <thread>
#include <condition_variable>
class MCTest {
public:
MCTest() : m_work(true), m_max_num(30), m_next_index(0) {
}
void producer_thread() {
while (m_work) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::unique_lock<std::mutex> lk(m_cvMutex);
m_cv.wait(lk);
m_data.push_back(m_next_index++);
std::cout << "producer " << m_next_index << ", queue size: " << m_data.size() << std::endl;
m_cv.notify_all();
}
}
void consumer_thread() {
while (m_work) {
std::unique_lock<std::mutex> lk(m_cvMutex);
m_cv.wait(lk);
int data = m_data.front();
m_data.pop_front();
std::cout << "consumer " << data << ", deque size: " << m_data.size() << std::endl;
m_cv.notify_all();
}
}
private:
bool m_work;
std::mutex m_cvMutex;
std::condition_variable m_cv;
std::deque<int> m_data;
size_t m_max_num;
int m_next_index;
};
int main() {
MCTest obj;
std::thread tp = std::thread(&MCTest::producer_thread, &obj);
std::thread tc = std::thread(&MCTest::consumer_thread, &obj);
tp.join();
tc.join();
return 0;
}
运行结果:
2.测试程序2
#include <mutex>
#include <deque>
#include <iostream>
#include <thread>
#include <condition_variable>
class MCTest {
public:
MCTest() : m_work(true), m_max_num(30), m_next_index(0) {
}
void producer_thread() {
while (m_work) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::unique_lock<std::mutex> lk(m_cvMutex);
m_cv.wait(lk, [this]() -> bool { return this->m_data.size() < this->m_max_num; });
m_data.push_back(m_next_index++);
std::cout << "producer " << m_next_index << ", queue size: " << m_data.size() << std::endl;
m_cv.notify_all();
}
}
void consumer_thread() {
while (m_work) {
std::unique_lock<std::mutex> lk(m_cvMutex);
m_cv.wait(lk, [this] { return !this->m_data.empty(); });
int data = m_data.front();
m_data.pop_front();
std::cout << "consumer " << data << ", deque size: " << m_data.size() << std::endl;
m_cv.notify_all();
}
}
private:
bool m_work;
std::mutex m_cvMutex;
std::condition_variable m_cv;
std::deque<int> m_data;
size_t m_max_num;
int m_next_index;
};
int main() {
MCTest obj;
std::thread tp = std::thread(&MCTest::producer_thread, &obj);
std::thread tc = std::thread(&MCTest::consumer_thread, &obj);
tp.join();
tc.join();
return 0;
}
运行结果:
3.运行结果思考
为什么测试1程序没有任何输出,出现死锁,而程序2正常交替执行?
程序1条件变量在得到通知之前会一直wait,如果线程1获取了锁后,阻塞于wait调用,释放了互斥锁,等待通知。此时线程2执行,线程2获取锁后,阻塞于阻塞于wait调用,并释放互斥锁,等待唤醒。本质上是处于死锁状态。
程序2条件变量处于wait阻塞时,除了得到通知会解除阻塞外,第二个参数为true时,wait函数也会返回,所以避免了死锁的存在。
总结一下,wait函数参数2含义如下:
(1)如果参数为true,即使没有收到通知,wait也会返回,此时本线程互斥量已经加锁
(2)如果参数为false,在没有收到通知时,解锁互斥量wait一直阻塞
(3)如果没有参数,与false一样