gpt4 book ai didi

c++ - QT5中实现原子队列

转载 作者:可可西里 更新时间:2023-11-01 18:40:00 24 4
gpt4 key购买 nike

我正在 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

在我插入和弹出一项后队列中断,我不明白为什么。我对 Atomic 风格的线程安全编程还很陌生,所以我很可能只是不了解这方面的特定方面。在 Debug模式下运行时,当我执行 result = next->data 时,我的 bool AtomicQueue::peek 函数出现 SEGSEV 段错误。

谁能指出我做错了什么?

更新:

所以我解决了问题,这是在我的 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

最佳答案

注意:这是我在发现代码中的问题后从我的问题中复制过来的。感谢 @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

关于c++ - QT5中实现原子队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19101284/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com