使用Qt的并发队列死锁
我正在尝试使用 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”而不是使用正常推送的原因是因为我希望能够使该线程阻塞,直到某些项目被处理为止,以避免消耗太多内存并进行不必要的磁盘 I/O。
谁能指出我出了什么问题吗?
I am trying to create a concurrent queue with Qt's concurrent threading constructs.
#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
I have my producer thread using the wait_and_push method to push data into the queue, and I have been trying to get my consumer to read from the queue using try_pop
while(!tiles->empty() || !tiles->getClosed())
{
if(!tiles->try_pop(tile))
continue;
//do stuff with the tile
}
However, this deadlocks sometimes. The producer sets the closed boolean as a flag to the consumer threads that it is finished loading the queue. My consumer only has that as a way to know whether teh queue is being loaded, still in progress, or hasnt been started.
The reason the producer has a "wait_and_push" isntead of using the normal push is because I wanted to be able to make that thread block until some items had been processed to avoid eating up so much memory, and doing unnecessary disk I/O.
Can anyone point me to what is going wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您忘记添加
try_pop
。如果有多个生产者/消费者访问您的队列,您应该为生产者和消费者设置单独的 QWaitCondition,否则wakeOne 可能无法唤醒正确的线程。
编辑:
如果有多个生产者/消费者,那么您应该有一个
notFullCondvar
和一个notEmptyCondvar
。try_pop
方法唤醒notFullCondvar
。wait_and_pop
方法等待notEmptyCondvar
,但唤醒notFullCondvar
。push
方法唤醒notEmptyCondvar
。wait_and_push
方法等待notFullCondvar
,但唤醒notEmptyCondvar
。我希望这是有道理的。
You forgot to add
in
try_pop
.If there will be multiple producers / consumers accessing your queue, you should have a separate
QWaitCondition
for producers and consumers, otherwisewakeOne
might not wake the correct thread.EDIT:
If there will be multiple producers / consumers, then you should have a
notFullCondvar
, and annotEmptyCondvar
.try_pop
method wakes thenotFullCondvar
.wait_and_pop
method waits on thenotEmptyCondvar
, but wakes thenotFullCondvar
.push
method wakes thenotEmptyCondvar
.wait_and_push
method waits on thenotFullCondvar
, but wakes thenotEmptyCondvar
.I hope this makes sense.