我正在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模式下运行时,当我执行bool AtomicQueue::peek时,我的result = next->data函数中出现SEGSEV segfault。
谁能指出我做错了什么?
更新:
因此,我解决了这个问题,该问题在我的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
    

    最佳答案

    注意:一旦我在代码中发现问题,就从问题中复制出该内容。感谢@ peter-k指出此问题并未得到正式答复。

    因此,我解决了这个问题,该问题在我的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
    

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

    10-09 13:37