C++ 使用Qt的并发队列是死锁的

C++ 使用Qt的并发队列是死锁的,c++,multithreading,qt,queue,C++,Multithreading,Qt,Queue,我试图用Qt的并发线程构造创建一个并发队列 #ifndef CONCURRENTQUEUE_H #define CONCURRENTQUEUE_H #include <QMutex> #include <QWaitCondition> #include <queue> template<typename Data> class ConcurrentQueue { private: std::queue<Data> the_qu

我试图用Qt的并发线程构造创建一个并发队列

#ifndef CONCURRENTQUEUE_H
#define CONCURRENTQUEUE_H
#include <QMutex>
#include <QWaitCondition>
#include <queue>

template<typename Data>
class ConcurrentQueue
{
private:
    std::queue<Data> the_queue;
    QMutex the_mutex;
    QWaitCondition the_condition_variable;
    bool closed;

public:

    void setClosed(bool state)
    {
        QMutexLocker locker(&the_mutex);
        closed = state;    
    }

    bool getClosed()
    {
        QMutexLocker locker(&the_mutex);
        return closed;    
    }

    void push(Data const& data)
    {
        QMutexLocker locker(&the_mutex);
        the_queue.push(data);
        the_condition_variable.wakeOne();    
    }

    bool empty()
    {
        QMutexLocker locker(&the_mutex);
        return the_queue.empty();    
    }

    bool try_pop(Data& popped_value)
    {
        QMutexLocker locker(&the_mutex);
        if(the_queue.empty())
        {
            return false;
        }
        popped_value = the_queue.front();
        the_queue.pop();
        return true;
    }

    void wait_and_pop(Data& popped_value)
    {
        QMutexLocker locker(&the_mutex);
        while(the_queue.empty())
        {
            the_condition_variable.wait(&the_mutex);
        }
        popped_value = the_queue.front();
        the_queue.pop();
        the_condition_variable.wakeOne();
    }

    //created to allow for a limited queue size
    void wait_and_push(Data const& data, const int max_size)
    {
        QMutexLocker locker(&the_mutex);
        while(the_queue.size() >= max_size)
        {
            the_condition_variable.wait(&the_mutex);
        }
        the_queue.push(data);
        the_condition_variable.wakeOne();
    }


};

#endif // CONCURRENTQUEUE_H
然而,这有时会造成僵局。生产者将闭合布尔值设置为消费者线程的标志,表明其已完成加载队列。我的消费者只知道队列是否正在加载、仍在进行中或尚未启动

生产者之所以有一个“wait_and_push”(等待和推送)替代使用普通推送,是因为我希望能够使线程阻塞,直到某些项目被处理,以避免占用如此多的内存,并进行不必要的磁盘I/O

有人能告诉我出了什么问题吗?

你忘了添加

the_condition_variable.wakeOne();
中尝试弹出

如果将有多个生产者/消费者访问您的队列,您应该为生产者和消费者分别设置一个
QWaitCondition
,否则
wakeOne
可能无法唤醒正确的线程

编辑:

如果将有多个生产者/消费者,那么您应该有一个
notFullCondvar
,和一个
notEmptyCondvar

  • try\u pop
    方法唤醒
    notFullCondvar
  • wait\u和\u pop
    方法等待
    notEmptyCondvar
    ,但唤醒
    notFullCondvar
  • push
    方法唤醒
    notEmptyCondvar
  • wait\u和\u push
    方法在
    notFullCondvar
    上等待,但会唤醒
    notEmptyCondvar
我希望这是有意义的。

您忘记添加

the_condition_variable.wakeOne();
中尝试弹出

如果将有多个生产者/消费者访问您的队列,您应该为生产者和消费者分别设置一个
QWaitCondition
,否则
wakeOne
可能无法唤醒正确的线程

编辑:

如果将有多个生产者/消费者,那么您应该有一个
notFullCondvar
,和一个
notEmptyCondvar

  • try\u pop
    方法唤醒
    notFullCondvar
  • wait\u和\u pop
    方法等待
    notEmptyCondvar
    ,但唤醒
    notFullCondvar
  • push
    方法唤醒
    notEmptyCondvar
  • wait\u和\u push
    方法在
    notFullCondvar
    上等待,但会唤醒
    notEmptyCondvar

< P>我希望这是有意义的。

这对你的问题没有直接帮助,但是你可能会考虑让队列只负责线程安全访问和移动逻辑来节制产生和消费到生产和消费类。@ Arnold Spence:内置“节流”并不罕见。这限制了队列的大小。这是一个众所周知的习惯用法,称为有界阻塞队列。请参阅,。尝试使用QSemaphore。对于这个任务,它可能比QWAITTHEATE更好(更方便)。这对您的问题没有直接帮助,但您可能需要考虑只让队列负责线程安全访问和移动逻辑,以产生和消费到生成和消费类中。@ Arnold Spence:内置是不寻常的。限制队列大小的“节流”。这是一个众所周知的习惯用法,称为有界阻塞队列。请参阅。尝试使用QSemaphore。对于此任务,它可能比QWaitCondition更好(更方便)。有一个生产者和多个消费者。您是说所有的方法应该有一个QWaitCondition,而推送方法应该有一个单独的QWaitCondition?有一个生产者和多个消费者。你是说所有的“pop”方法都应该有一个QWaitCondition,而push方法应该有一个单独的QWaitCondition?