2013-09-30 23 views
7

我建立在Qt中一个相当复杂的应用程序,它可以动态加载动态库和运行它们的线程,它们必须尽快通过相互之间的信息尽可能的原子队列,所以我想一个原子队列会是我最好的情况,所以这是AtomicQueue.hpp文件:实现在QT5

#ifndef ATOMICQUEUE_HPP 
#define ATOMICQUEUE_HPP 

#include <QAtomicPointer> 


// Used http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448?pgno=2 
// as reference 
template<class T> 
class AtomicQueue 
{ 
    struct QueueNode 
    { 
     QueueNode(const T& value) : next(NULL), data(value) {} 
     ~QueueNode() { if (next) delete next; } 
     QueueNode *next; 
     T   data; 
    }; 

public: 
    AtomicQueue() 
    { 
     m_front = new QueueNode(T()); 
     m_tail.store(m_front); 
     m_divider.store(m_front); 
    } 

    ~AtomicQueue() {} 

    void push(const T& value) 
    { 
     m_tail.load()->next = new QueueNode(value); 
     m_tail = m_tail.load()->next; // This moves the QueueNode into the atomic pointer, making it safe :) 
     while(m_front != m_divider.load()) 
     { 
      QueueNode *tmp = m_front; 
      m_front = m_front->next; 
      delete tmp; 
     } 
    } 

    bool peek(T& result) 
    { 
     if (m_divider.load() != m_tail.load()) 
     { 
      // Problem area 
      QueueNode *next = m_divider.load()->next; 
      if (next) 
      { 
       result = next->data; 
       return true; 
      } 
     } 
     return false; 
    } 

    bool pop(T& result) 
    { 
     bool res = this->peek(result); 
     if (res) 
     { 
      m_divider = m_divider.load()->next; 
     } 
     return res; 
    } 

private: 
    QueueNode     *m_front; 
    QAtomicPointer<QueueNode> m_divider, m_tail; 
}; 

#endif // ATOMICQUEUE_HPP 

队列休息后,我推和弹出一个项目,我想不通为什么。我是很新的原子式的线程安全编程,所以这很可能是我只是不明白这一个特定的方面。在调试模式下运行时,我得到一个SEGSEV段错误在我bool AtomicQueue::peek功能,当我做result = next->data

任何人都可以指出我做错了什么?

更新:

所以我固定的问题,这是我QueueNode析构函数。本质上讲,当我删除一个节点,它会试图清理所有其他节点,然后给了我几个不同的路线固定它:

  1. 坐落在QueueNode一个标志,告诉它不要删除所有->next节点
  2. 拆离删除前的前节
  3. 允许AtomicQueue管理节点

我选择了第三个选项,因为它已经做了一些清理工作,同时推动新节点的清理,所以这里是固定类对于任何感兴趣的人:

#ifndef ATOMICQUEUE_HPP 
#define ATOMICQUEUE_HPP 

#include <QAtomicPointer> 


// Used http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448?pgno=2 
// as reference 
template<class T> 
class AtomicQueue 
{ 
    struct QueueNode 
    { 
     QueueNode(const T& value) : next(NULL), data(value) {} 
     ~QueueNode() { /*if (next) delete next;*/ } 
     QueueNode *next; 
     T   data; 
    }; 

public: 
    AtomicQueue() 
    { 
     m_front = new QueueNode(T()); 
     m_tail.store(m_front); 
     m_divider.store(m_front); 
    } 

    ~AtomicQueue() 
    { 
     QueueNode *node = m_front; 
     while(node->next) 
     { 
      QueueNode *n = node->next; 
      delete node; 
      node = n; 
     } 
    } 

    void push(const T& value) 
    { 
     m_tail.load()->next = new QueueNode(value); 
     m_tail = m_tail.load()->next; // This moves the QueueNode into the atomic pointer, making it safe :) 
     while(m_front != m_divider.load()) 
     { 
      QueueNode *tmp = m_front; 
      m_front = m_front->next; 
      delete tmp; 
     } 
    } 

    bool peek(T& result) 
    { 
     if (m_divider.load() != m_tail.load()) 
     { 
      // Problem area 
      QueueNode *next = m_divider.load()->next; 
      if (next) 
      { 
       result = next->data; 
       return true; 
      } 
     } 
     return false; 
    } 

    bool pop(T& result) 
    { 
     bool res = this->peek(result); 
     if (res) 
     { 
      m_divider = m_divider.load()->next; 
     } 
     return res; 
    } 

private: 
    QueueNode     *m_front; 
    QAtomicPointer<QueueNode> m_divider, m_tail; 
}; 

#endif // ATOMICQUEUE_HPP 
+2

请回答自己的问题,如果你已经找到了答案。 –

+0

非常感谢您对原子队列的实现:d –

+0

我的荣幸。现在已经有几年了,但希望它仍然能够与Qt/C++的其他部分保持一致。不过,不确定新的C++标准是否可以为此提供更好的功能。 – OzBarry

回答

0

注:这是刚刚从我的问题复制一次我在我的代码想通了这个问题。感谢@ peter-k指出这并没有正式得到答案。

所以我固定的问题,这是我QueueNode析构函数。本质上讲,当我删除一个节点,它会试图清理所有其他节点,然后给了我几个不同的路线固定它:

  1. 坐落在QueueNode一个标志,告诉它不要删除所有->next节点
  2. 拆离删除前的前节
  3. 允许AtomicQueue管理节点

我选择了第三个选项,因为它已经做了一些清理工作,同时推动新节点的清理,所以这里是固定类对于任何感兴趣的人:

#ifndef ATOMICQUEUE_HPP 
#define ATOMICQUEUE_HPP 

#include <QAtomicPointer> 


// Used http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448?pgno=2 
// as reference 
template<class T> 
class AtomicQueue 
{ 
    struct QueueNode 
    { 
     QueueNode(const T& value) : next(NULL), data(value) {} 
     ~QueueNode() { /*if (next) delete next;*/ } 
     QueueNode *next; 
     T   data; 
    }; 

public: 
    AtomicQueue() 
    { 
     m_front = new QueueNode(T()); 
     m_tail.store(m_front); 
     m_divider.store(m_front); 
    } 

    ~AtomicQueue() 
    { 
     QueueNode *node = m_front; 
     while(node->next) 
     { 
      QueueNode *n = node->next; 
      delete node; 
      node = n; 
     } 
    } 

    void push(const T& value) 
    { 
     m_tail.load()->next = new QueueNode(value); 
     m_tail = m_tail.load()->next; // This moves the QueueNode into the atomic pointer, making it safe :) 
     while(m_front != m_divider.load()) 
     { 
      QueueNode *tmp = m_front; 
      m_front = m_front->next; 
      delete tmp; 
     } 
    } 

    bool peek(T& result) 
    { 
     if (m_divider.load() != m_tail.load()) 
     { 
      // Problem area 
      QueueNode *next = m_divider.load()->next; 
      if (next) 
      { 
       result = next->data; 
       return true; 
      } 
     } 
     return false; 
    } 

    bool pop(T& result) 
    { 
     bool res = this->peek(result); 
     if (res) 
     { 
      m_divider = m_divider.load()->next; 
     } 
     return res; 
    } 

private: 
    QueueNode     *m_front; 
    QAtomicPointer<QueueNode> m_divider, m_tail; 
}; 

#endif // ATOMICQUEUE_HPP