C ++ 11 condtional变量

时间:2016-08-31 07:01:59

标签: multithreading c++11 condition-variable


我正在尝试在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;
}

1 个答案:

答案 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完成了填充队列。线程永远不会加入。

有很多方法可以解决这个问题。我相信你会自己找到一个。