如何在不使用Lambda的情况下调用std::condition_variable::wait(lock, pred)
解决std::condition_variable无Lambda谓词的生产者消费者问题
问题背景
现有一段基于std::condition_variable实现的生产者消费者C++代码,逻辑可正常运行,但编码规范禁止使用Lambda表达式。原代码中std::condition_variable::wait方法使用Lambda作为谓词,尝试直接传入bool变量(如wait(g_ready))无法正常工作,需修改为符合规范的实现方式。
原代码
#include <condition_variable> #include <cstdlib> #include <iostream> #include <mutex> #include <thread> using namespace std; std::mutex g_mutex; std::condition_variable g_cv; bool g_ready = false; int g_data = 0; int produceData() { int randomNumber = rand() % 1000; std::cout << "produce data: " << randomNumber << "\n"; return randomNumber; } void consumeData(int data) { std::cout << "receive data: " << data << "\n"; } void consumer() { int data = 0; while (true) { std::unique_lock<std::mutex> ul(g_mutex); g_cv.wait(ul, []() { return g_ready; }); consumeData(g_data); g_ready = false; ul.unlock(); g_cv.notify_one(); } } void producer() { while (true) { std::unique_lock<std::mutex> ul(g_mutex); g_data = produceData(); g_ready = true; ul.unlock(); g_cv.notify_one(); ul.lock(); g_cv.wait(ul, []() { return g_ready == false; }); } } void consumerThread(int n) { consumer(); } void producerThread(int n) { producer(); } int main() { int times = 100; std::thread t1(consumerThread, times); std::thread t2(producerThread, times); t1.join(); t2.join(); return 0; }
错误尝试
直接传入bool变量:
g_cv.wait(ul, g_ready);
此方式无法正常工作,因为wait的谓词参数需要是可调用对象(能通过()触发调用),而bool是值类型,不满足可调用要求,同时无法处理线程的虚假唤醒问题。
解决方案
可以通过仿函数(函数对象)或全局普通函数替代Lambda作为谓词,两种方式均符合编码规范且能正确处理虚假唤醒。
方案1:使用仿函数(推荐,封装性更好)
定义两个结构体作为谓词,重载operator()实现检查逻辑:
#include <condition_variable> #include <cstdlib> #include <iostream> #include <mutex> #include <thread> using namespace std; std::mutex g_mutex; std::condition_variable g_cv; bool g_ready = false; int g_data = 0; // 检查g_ready是否为true的谓词 struct IsReady { bool operator()() const { return g_ready; } }; // 检查g_ready是否为false的谓词 struct IsNotReady { bool operator()() const { return !g_ready; } }; int produceData() { int randomNumber = rand() % 1000; std::cout << "produce data: " << randomNumber << "\n"; return randomNumber; } void consumeData(int data) { std::cout << "receive data: " << data << "\n"; } void consumer() { int data = 0; while (true) { std::unique_lock<std::mutex> ul(g_mutex); // 使用IsReady仿函数替代Lambda g_cv.wait(ul, IsReady()); consumeData(g_data); g_ready = false; ul.unlock(); g_cv.notify_one(); } } void producer() { while (true) { std::unique_lock<std::mutex> ul(g_mutex); g_data = produceData(); g_ready = true; ul.unlock(); g_cv.notify_one(); ul.lock(); // 使用IsNotReady仿函数替代Lambda g_cv.wait(ul, IsNotReady()); } } void consumerThread(int n) { consumer(); } void producerThread(int n) { producer(); } int main() { int times = 100; std::thread t1(consumerThread, times); std::thread t2(producerThread, times); t1.join(); t2.join(); return 0; }
方案2:使用全局普通函数
定义全局函数实现检查逻辑,直接传入函数指针作为谓词:
#include <condition_variable> #include <cstdlib> #include <iostream> #include <mutex> #include <thread> using namespace std; std::mutex g_mutex; std::condition_variable g_cv; bool g_ready = false; int g_data = 0; // 检查g_ready是否为true bool isReady() { return g_ready; } // 检查g_ready是否为false bool isNotReady() { return !g_ready; } int produceData() { int randomNumber = rand() % 1000; std::cout << "produce data: " << randomNumber << "\n"; return randomNumber; } void consumeData(int data) { std::cout << "receive data: " << data << "\n"; } void consumer() { int data = 0; while (true) { std::unique_lock<std::mutex> ul(g_mutex); // 传入函数指针 g_cv.wait(ul, isReady); consumeData(g_data); g_ready = false; ul.unlock(); g_cv.notify_one(); } } void producer() { while (true) { std::unique_lock<std::mutex> ul(g_mutex); g_data = produceData(); g_ready = true; ul.unlock(); g_cv.notify_one(); ul.lock(); // 传入函数指针 g_cv.wait(ul, isNotReady); } } void consumerThread(int n) { consumer(); } void producerThread(int n) { producer(); } int main() { int times = 100; std::thread t1(consumerThread, times); std::thread t2(producerThread, times); t1.join(); t2.join(); return 0; }
关键说明
std::condition_variable::wait的谓词必须是可调用对象,返回bool值:wait会在被唤醒后调用该对象,若返回true则继续执行,否则重新进入等待状态,以此处理虚假唤醒问题。- 直接传入bool变量既不满足可调用要求,也无法处理虚假唤醒,会导致线程逻辑错误。
内容的提问来源于stack exchange,提问作者SiennaRose
相关产品推荐
相关产品推荐

