我建立在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析构函数。本质上讲,当我删除一个节点,它会试图清理所有其他节点,然后给了我几个不同的路线固定它:
- 坐落在QueueNode一个标志,告诉它不要删除所有
->next
节点 - 拆离删除前的前节
- 允许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
请回答自己的问题,如果你已经找到了答案。 –
非常感谢您对原子队列的实现:d –
我的荣幸。现在已经有几年了,但希望它仍然能够与Qt/C++的其他部分保持一致。不过,不确定新的C++标准是否可以为此提供更好的功能。 – OzBarry