2011-08-18 112 views
0

我想创建一个并发队列与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。

任何人都可以指出我出了什么问题吗?

+0

这不会直接帮助您解决问题,但您可能需要考虑使队列仅负责线程安全访问,并将用于限制生产和消费的逻辑移动到生产和消费类中。 –

+0

@Arnold Spence:有限制队列大小的内置“限制”并不罕见。这是一个众所周知的习惯称为*有界阻塞队列*。请参阅http://drdobbs.com/cpp/184401814,http://zthread.sourceforge.net/html/classZThread_1_1BoundedQueue.html,http://download.oracle.com/javase/6/docs/api/java/util /concurrent/BlockingQueue.html。 –

+0

尝试使用QSemaphore。对于这个任务来说,它可能比QWaitCondition更好(更方便)。 – QtRoS

回答

2

你忘了添加

the_condition_variable.wakeOne(); 

try_pop

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

编辑:

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

  • try_pop方法唤醒notFullCondvar
  • wait_and_pop方法等待notEmptyCondvar,但醒来notFullCondvar
  • push方法唤醒notEmptyCondvar
  • wait_and_push方法在notFullCondvar上等待,但唤醒notEmptyCondvar

我希望这是有道理的。

+0

有一个生产者和多个消费者。你是说所有的“流行”方法都应该有一个QWaitCondition,而推送方法应该有一个单独的QWaitCondition? – Derek

+0

@Derek:Sorta ...查看我的编辑。 –