c++ - 条件变量基本示例
问题描述
我正在学习 C++11 中的条件变量,并根据示例代码编写了这个程序。
目标是将生产者生成并由消费者推入向量的前十个自然整数累积到向量中。但是它不起作用,因为例如在某些运行中,向量仅包含 1、7 和 10。
#include <mutex>
#include <condition_variable>
#include<vector>
#include <iostream>
#include <cstdio>
std::mutex mut;
#define MAX 10
int counter;
bool isIncremented = false;
std::vector<int> vec;
std::condition_variable condvar;
void producer() {
while (counter < MAX) {
std::lock_guard<std::mutex> lg(mut);
++counter;
isIncremented = true;
condvar.notify_one();
}
}
void consumer() {
while (true) {
std::unique_lock<std::mutex> ul(mut);
condvar.wait(ul, [] { return isIncremented; });
vec.push_back(counter);
isIncremented = false;
if (counter >= MAX) {
break;
}
}
}
int main(int argc, char *argv[]) {
std::thread t1(consumer);
std::thread t2(producer);
t2.join();
t1.join();
for (auto i : vec) {
std::cout << i << ", ";
}
std::cout << std::endl;
// Expected output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
// Example of actual output: 1, 7, 10,
std::cout << "Press enter to quit";
getchar();
return 0;
}
解决方案
问题是你只记得你的生产者生产的最后一个数字。你的生产者永远不会等到消费者消费完它生产的东西。如果您的生产者线程在消费者线程开始运行之前对其循环进行了多次迭代(这并非不可能,因为循环没有做太多),消费者将只会看到生产者产生的最后一个数字并且只会推送那个进入向量...</p>
为了解决这个问题,要么使用第二个条件变量让生产者等待某人获取它产生的最后一个结果,要么使用可以在生产者和消费者之间存储多个结果的东西,或者两者的组合......</p >
注意:通知条件变量不是阻塞调用。如果是这样,它必须要求您交出互斥锁,以便它可以在内部释放它,否则您最终会陷入死锁。notify_one()
只会唤醒正在等待条件变量的线程之一并返回。被唤醒线程阻塞的等待调用将在它返回之前重新获取互斥锁。在您的情况下,消费者线程不太可能被唤醒,然后无法重新获取互斥锁并立即再次阻塞,因为您的生产者线程在调用时仍然持有互斥锁notify_one()
。因此,作为一般经验法则,如果您在调用 notify 之前持有与条件变量关联的互斥锁,您希望释放它……</p>
推荐阅读
- javascript - 为什么这个简单的 hello world Vue 应用程序会因未找到挂载而失败?
- amazon-web-services - 在 appspec.yml 中提到可执行文件的位置
- c++ - 在 Visual Studio Code Linux 上激活 conda 环境
- android - Fire base google 身份验证不会传递真实的虚构信息
- java - 尝试使用正则表达式查找最后一个大写字符的索引
- docker - 将 Docker-compose 部署到生产环境中
- python - 我可以将 Twitter 的学术研究完整存档端点 v2 与 tweepy 一起使用吗?
- python - 表格首字母不显示
- reactjs - 如何使用 React Link 组件提交表单?
- angular - ThreeJS-翻译对象并在一定时间后卸载它们