并发队列使用Qt是死锁

Concurrent Queue using Qt is deadlocking

本文关键字:死锁 Qt 队列 并发      更新时间:2023-10-16

我正在尝试创建一个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方法将数据推送到队列中,我一直试图让我的消费者使用try_pop

从队列中读取数据
 while(!tiles->empty() || !tiles->getClosed())
{
             if(!tiles->try_pop(tile))
                    continue;
//do stuff with the tile
}

然而,这有时会死锁。生产者将关闭的布尔值设置为一个标志,告诉消费者线程它已经完成了队列的加载。我的消费者只是用它来了解队列是否正在加载、仍在进行中或尚未启动。

生产者使用"wait_and_push"而不是使用正常的push的原因是因为我希望能够使线程阻塞,直到一些项目被处理,以避免消耗太多内存,并做不必要的磁盘I/o。

谁能告诉我哪里出了问题?

你忘了添加

the_condition_variable.wakeOne();

in try_pop .

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

编辑:

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

  • try_pop方法唤醒notFullCondvar
  • wait_and_pop等待notEmptyCondvar,唤醒notFullCondvar
  • push方法唤醒notEmptyCondvar
  • wait_and_push方法等待notFullCondvar,唤醒notEmptyCondvar