Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading C++;11条件变量_Multithreading_C++11_Condition Variable - Fatal编程技术网

Multithreading C++;11条件变量

Multithreading C++;11条件变量,multithreading,c++11,condition-variable,Multithreading,C++11,Condition Variable,我试图在C++11中学习并发性时犯很多错误。我不得不问这个, 下面是这个人应该做的: 一个队列,三个线程,一个是假设将一个整数放入队列,另外两个是假设通过弹出队列相应地增加s1,s2,这样我就可以得到队列中的总数。为了简化,我将1到10个数字放入队列中。 但有时它是有效的,有时似乎有一个无限循环::原因是什么? #包括 #包括 #包括 #包括 #包括 #包括 #包括 类线程安全队列{ 私人: 可变std::互斥mut; std::队列数据\队列; std::条件变量数据条件; std::st


我试图在C++11中学习并发性时犯很多错误。我不得不问这个,

下面是这个人应该做的: 一个队列,三个线程,一个是假设将一个整数放入队列,另外两个是假设通过弹出队列相应地增加s1,s2,这样我就可以得到队列中的总数。为了简化,我将1到10个数字放入队列中。

但有时它是有效的,有时似乎有一个无限循环::原因是什么?

#包括
#包括
#包括
#包括
#包括
#包括
#包括
类线程安全队列{
私人:
可变std::互斥mut;
std::队列数据\队列;
std::条件变量数据条件;
std::string log;//看看后面发生了什么
布尔多;
公众:
线程安全队列(){
log=“初始化队列\n”;
完成=错误;
}
线程安全队列(线程安全队列常量和其他){
std::锁紧装置lk(其他。mut);
数据队列=其他。数据队列;
}
无效设置完成(布尔常数s){
标准:锁紧装置lk(mut);
完成=s;
}
完成{
标准:锁紧装置lk(mut);
已完成的返回;
}
无效推送(int新值){
标准:锁紧装置lk(mut);
日志+=“+推送”+std::到字符串(新值)+“\n”;
数据队列推送(新值);
数据条件通知单();
}
无效等待和弹出(int和value){
std::唯一锁lk(mut);
data_cond.wait(lk,[this]{return!data_queue.empty();});
value=data_queue.front();
log+=“-poping”+std::to_字符串(值)+“\n”;
data_queue.pop();
}
std::shared_ptr wait_和_pop(){
std::唯一锁lk(mut);
data_cond.wait(lk,[this]{return!data_queue.empty();});
std::shared_ptr res(std::make_shared(data_queue.front());
log+=“-popping”+std::to_string(*res)+“\n”;
data_queue.pop();
返回res;
}
bool try_pop(int和value){
标准:锁紧装置lk(mut);
if(data_queue.empty()){
log+=“试图弹出,但为空\n”;
返回false;
}
value=data_queue.front();
log+=“-popping”+std::to_字符串(值)+“\n”;
data_queue.pop();
返回true;
}
std::shared_ptr try_pop(){
标准:锁紧装置lk(mut);
if(data_queue.empty()){
log+=“试图弹出,但为空\n”;
返回std::shared_ptr();
}
std::shared_ptr res(std::make_shared(data_queue.front());
log+=“-popping”+std::to_string(*res)+“\n”;
data_queue.pop();
返回res;
}
bool empty()常量{
标准:锁紧装置lk(mut);
//log+=“检查队列是否为空\n”;
返回数据_queue.empty();
}
std::string get_log(){
返回日志;
}
};
线程安全队列tq;
int s1,s2;
无效准备(){

对于(int i=1;i请查看函数p1第5行

if(tq.get_done()&&tq.empty())中断

所以你检查了队列是否为空。它不是。现在你循环并输入

tq.等待和弹出(数据)

你会在哪里找到

data_cond.wait(lk,[this]{return!data_queue.empty();})

这基本上是

while(data_queue.empty()){ 等待(lk); }

请注意缺少的“!”

现在,您的线程坐在那里等待队列不为空,这永远不会发生,因为生产者id已填充队列。线程将永远不会加入


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

在设置
done
时,你可能需要通知
data\u cond
,并在
data\u cond.wait
条件中检查它。我认为如果在
push()
之前调用
wait\u pop()
,以及
push(),就会出现死锁
无法通过互斥锁调用
notify\u one
wait\u和\u pop()
从其等待中释放出来。我认为在获取互斥锁之前,您应该
wait()
。@KenY-N,是的,这是我所怀疑的。但是我如何确保push()应该先工作吗?@Nano就像我说的,试着交换
std::unique_lock lk(mut);
data_cond.wait(lk,[this]{return!data_queue.empty()});
。这可以确保在推送某个东西之前代码不会弹出。(我想,这都是我的想法!),你可能想要
data_cond.wait(lk,[this]{std::unique_lock lk(mut);return!data_queue.empty()})
,或者重新设计您的整个代码!@KenY-N不,您不能交换这些行,它们的顺序是正确的。请阅读
std::condition_variable::wait
如何工作。啊,是的,这也是正确的。如果
p2
清空
p1
之间的队列
tq.empty()
和下一个
tq。等等,\u和_pop(data);
会有另一个挂起。@Nano:如果我的答案满足你的问题,考虑在我的答案旁边加上绿色的小勾号。ty
#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;
}