我正在尝试在C ++ 11中学习并发时犯了很多错误。我不得不问这个,
这是这个应该做的:
一个队列和三个线程,一个假设将一个整数放入队列,其他两个假设通过弹出队列相应地增加s1,s2,这样我就可以得到队列中的数字的总和。为了简单起见,我将1到10个数字放入队列中。
但有时它有效,有时看起来有一个无限循环::原因是什么?
#include <queue>
#include <memory>
#include <mutex>
#include <thread>
#include <iostream>
#include <condition_variable>
#include <string>
class threadsafe_queue {
private:
mutable std::mutex mut;
std::queue<int> data_queue;
std::condition_variable data_cond;
std::string log; //just to see what is going on behind
bool done;
public:
threadsafe_queue(){
log = "initializing queue\n";
done = false;
}
threadsafe_queue(threadsafe_queue const& other) {
std::lock_guard<std::mutex> lk(other.mut);
data_queue = other.data_queue;
}
void set_done(bool const s) {
std::lock_guard<std::mutex> lk(mut);
done = s;
}
bool get_done() {
std::lock_guard<std::mutex> lk(mut);
return done;
}
void push(int new_value) {
std::lock_guard<std::mutex> lk(mut);
log += "+pushing " + std::to_string(new_value) + "\n";
data_queue.push(new_value);
data_cond.notify_one();
}
void wait_and_pop(int& value) {
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty();});
value = data_queue.front();
log += "-poping " + std::to_string(value) + "\n";
data_queue.pop();
}
std::shared_ptr<int> wait_and_pop() {
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty();});
std::shared_ptr<int> res(std::make_shared<int>(data_queue.front()));
log += "- popping " + std::to_string(*res) + "\n";
data_queue.pop();
return res;
}
bool try_pop(int& value) {
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty()) {
log += "tried to pop but it was empty\n";
return false;
}
value = data_queue.front();
log += "-popping " + std::to_string(value) + "\n";
data_queue.pop();
return true;
}
std::shared_ptr<int> try_pop() {
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty()) {
log += "tried to pop but it was empty\n";
return std::shared_ptr<int>();
}
std::shared_ptr<int> res(std::make_shared<int>(data_queue.front()));
log += "-popping " + std::to_string(*res) + "\n";
data_queue.pop();
return res;
}
bool empty() const {
std::lock_guard<std::mutex> lk(mut);
//log += "checking the queue if it is empty\n";
return data_queue.empty();
}
std::string get_log() {
return log;
}
};
threadsafe_queue tq;
int s1, s2;
void prepare() {
for (int i = 1; i <= 10; i++)
tq.push(i);
tq.set_done(true);
}
void p1() {
while (true) {
int data;
tq.wait_and_pop(data);
s1 += data;
if (tq.get_done() && tq.empty()) break;
}
}
void p2() {
while (true) {
int data;
tq.wait_and_pop(data);
s2 += data;
if (tq.get_done() && tq.empty()) break;
}
}
int main(int argc, char *argv[]) {
std::thread pp(prepare);
std::thread worker(p1);
std::thread worker2(p2);
pp.join();
worker.join();
worker2.join();
std::cout << tq.get_log() << std::endl;
std::cout << s1 << " " << s2 << std::endl;
return 0;
}
答案 0 :(得分:1)
查看功能p1第5行
if(tq.get_done()&amp;&amp; tq.empty())中断;
所以你检查了队列是否为空。它不是。现在你循环并输入
tq.wait_and_pop(数据);
你会发现
data_cond.wait(lk,[this] {return!data_queue.empty();});
基本上是
while(data_queue.empty()){ 等待(LK); }
注意缺少的&#39;!&#39;。
现在你的线程坐在那里并等待队列不为空,这将永远不会发生,因为生成器id完成了填充队列。线程永远不会加入。
有很多方法可以解决这个问题。我相信你会自己找到一个。