【发布时间】:2018-03-28 01:03:07
【问题描述】:
我正在学习 C++ (14),目前我正在研究并发部分。
我写了一个producer/consumer 的小例子来学习和理解condition_variables。
这个想法是让一个线程用数字填充一个向量,然后另一个线程将它打印到控制台:
#include <iostream>
#include <thread>
#include <condition_variable>
#include <vector>
#include <atomic>
std::atomic<bool> done{false};
std::mutex ready_mutex;
std::condition_variable ready;
std::vector<int> numbers;
void produce() {
auto idx = 0;
while( true ) {
++idx;
std::lock_guard<std::mutex> lk(ready_mutex);
for(int i = 0; i < 5; ++i) {
numbers.push_back(i);
}
if( 5 == idx) {
done = true;
break;
}
ready.notify_one();
}
ready.notify_one();
}
void consume() {
while( true ) {
std::unique_lock<std::mutex> lk(ready_mutex);
ready.wait(lk, [](){ return !v.empty(); });
std::cout << "(" << numbers.size() << ")" << std::endl;
for(auto x: numbers) {
std::cout << x << ", ";
}
std::cout << std::endl;
numbers.clear();
std::cout << "(" << numbers.size() << ")" << std::endl;
std::cout.flush();
if(done) break;
}
}
int main() {
std::thread t(produce);
std::thread t2(consume);
t.join();
t2.join();
return 0;
}
问题是程序没有向我显示预期的输出。 我期待的是:
(5) 0, 1, 2, 3, 4, (0)
(5) 0, 1, 2, 3, 4, (0)
(5) 0, 1, 2, 3, 4, (0)
(5) 0, 1, 2, 3, 4, (0)
(5) 0, 1, 2, 3, 4, (0)
但我得到的是:
(25)
0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4,
(0)
就我所见,producer 线程一次性运行所有迭代,然后通知consumer 线程,但几个小时后我仍然不明白为什么producer 没有唤醒@ 987654329@直到结束。
此外,我注意到如果我不使用全局向量,而是将其作为对线程的引用传递,则此问题仍然存在:
void producerer(std::vector<int>& v);
void consumer(std::vector<int>& v);
std::vector<int> numbers;
std::thread t(producer, std::ref(numbers));
std::thread t2(consumerer, std::ref(numbers));
操作系统: Debian 9
编译器: g++ 6.3.0、clang++ 3.8.1-24
编译标志: -Werror -Wextra -Wall -std=c++14 -O0 -g3 -pthread
【问题讨论】:
-
produce保持互斥锁不断锁定,但只是最短暂的时刻。consume根本没有足够快地醒来,并且渴望访问。它只在produce完成后才设法获取互斥锁。
标签: multithreading c++14 producer-consumer