std::condition_variable
是 C++11 标准引入的,用于实现线程间的同步,用于线程实现带有条件的去竞争锁的问题。
当我们使用互斥锁时,多个线程只要发现锁空闲,就会去抢锁,争夺执行权限。如果抢到锁的线程没有满足某个条件,它就不具备执行权限,浪费系统资源。所以,我们希望线程在满足某个条件时,再去抢锁。
条件变量能够为互斥锁构建一个条件,当线程去争抢该锁时,必须满足相应的条件。如果不满足条件,则进入阻塞等待。当条件满足时,再被唤醒。
1. 问题场景
#if 1 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<thread> #include<queue> #include<mutex> #include<chrono> const size_t buffer_size = 5; std::queue<size_t> buffer; std::mutex buffer_mutex; void do_produce() { size_t index = 0; while (true) { buffer_mutex.lock(); if (buffer.size() < buffer_size) { std::cout << buffer.size() << " " << std::this_thread::get_id() << " 生产:" << index << std::endl; buffer.push(index++); } buffer_mutex.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(300)); } } void do_consume() { while (true) { buffer_mutex.lock(); if (buffer.size() > 0) { size_t element = buffer.front(); std::cout << std::this_thread::get_id() << " 消费:" << element << std::endl; buffer.pop(); } buffer_mutex.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } } // 不足 // 生产者和消费者都在每次操作前都尝试获取锁,这可能会导致频繁的上下文切换和锁竞争,降低程序的性能,特别是在多线程环境下 void test() { std::thread producer(do_produce); std::thread consumer1(do_consume); std::thread consumer2(do_consume); producer.join(); consumer1.join(); consumer2.join(); } int main() { test(); return EXIT_SUCCESS; } #endif
2. 问题解决
#if 0 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<thread> #include<queue> #include<mutex> #include<chrono> // 条件变量 std::condition_variable producer_condition; std::condition_variable consumer_condition; std::queue<int> buffer; std::mutex buffer_mutex; void do_produce() { int index = 0; while (true) { { std::unique_lock<std::mutex> lock(buffer_mutex); producer_condition.wait(lock, [&]() {return buffer.size() < 5; }); std::cout << std::this_thread::get_id() << " 生产:" << index << std::endl; buffer.push(index++); std::this_thread::sleep_for(std::chrono::milliseconds(300)); } consumer_condition.notify_all(); } } void do_consume() { while (true) { { std::unique_lock<std::mutex> lock(buffer_mutex); consumer_condition.wait(lock, [&]() {return !buffer.empty(); }); int element = buffer.front(); buffer.pop(); std::cout << std::this_thread::get_id() << " 消费:" << element << ", 剩余:" << buffer.size() << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(500)); } producer_condition.notify_one(); } } void test() { std::thread producer(do_produce); std::thread consumer1(do_consume); std::thread consumer2(do_consume); producer.join(); consumer1.join(); consumer2.join(); } int main() { test(); return EXIT_SUCCESS; } #endif