我在Qt中构建了一个相当复杂的应用程序,可以动态加载动态库并将它们作为线程运行,并且它们必须尽可能快地在彼此之间传递信息,所以我认为原子队列是我最好的情况,所以这是AtomicQueue.hpp文件:
#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
我推动并弹出一个项目后队列中断,我无法弄清楚原因。我对原子风格的线程安全编程很陌生,所以我很可能不理解这一点的具体方面。在调试模式下运行时,当我bool AtomicQueue::peek
时,我的result = next->data
函数中出现了SEGSEV段错误。
有谁可以指出我做错了什么?
所以我修复了问题,这是在我的QueueNode析构函数中。基本上当我删除一个节点时,它会尝试清理所有其他节点,然后给我一些不同的路由来修复它:
->next
个节点我选择了第三个选项,因为它在推送新节点时已经进行了一些清理,所以这里是感兴趣的人的固定类:
#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
答案 0 :(得分:0)
注意:一旦我在代码中发现了问题,这只是从我的问题中复制而来。谢谢@ peter-k指出这个没有得到正式回答。
所以我修复了问题,这是在我的QueueNode析构函数中。基本上当我删除一个节点时,它会尝试清理所有其他节点,然后给我一些不同的路由来修复它:
->next
个节点我选择了第三个选项,因为它在推送新节点时已经进行了一些清理,所以这里是感兴趣的人的固定类:
#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