I am creating a rather complex application in Qt that can dynamically load dynamic libraries and run them as streams, and they should pass information to each other as quickly as possible, so I decided that the atomic queue would be my best script, so this is the AtomicQueue.hpp file :
#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
The queue is interrupted after I click and add one item, and I cannot understand why. I'm completely new to Atomic streaming programming, so it's entirely possible that I just don't understand the specific aspect of this. When working in debug mode, I get segfault SEGSEV in my bool AtomicQueue::peek function when I do result = next->data .
Can someone point out what I'm doing wrong?
Update:
So, I fixed the problem that was in my QueueNode destructor. Essentially, when I deleted the node, it would try to clear all the other nodes, which gave me several different ways to fix it:
- Set a flag to QueueNode that tells it not to delete all nodes
->next - Before removing the front panel of a node
- Allow AtomicQueue to manage node cleanup
I chose the third option, since it already did some cleaning when clicking new nodes, so there is a fixed class for everyone who is interested in this:
#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 ++ multithreading atomic atomicity qt5
Ozbarry
source share