2015-07-03 74 views
0

我用QT編寫了一個共享內存環形緩衝區,我發現它在一個消費者和一個作者的單個進程中效果很好。如果我嘗試從第二個過程讀取數據,那麼第一個將連接崩潰的數據與seg故障相關聯。也許我忽略了一些東西?共享內存環形緩衝區崩潰

頭文件

#ifndef SHAREDMEMORYRINGBUFFER_H 
#define SHAREDMEMORYRINGBUFFER_H 

#include <QObject> 
#include <QSharedMemory> 

class SharedMemoryRingBuffer : public QObject 
{ 
    Q_OBJECT 
public: 
    struct SharedMemoryAttributes { 
     int32_t readPosition; 
     int32_t writePosition; 
     int32_t size; 
     int32_t* data; 
    }; 
    explicit SharedMemoryRingBuffer(QString sharedMemoryName, int32_t size, QObject *parent = 0); 
    ~SharedMemoryRingBuffer(); 
    int write(int32_t frame); 
    int32_t read(); 

    int32_t length(); 
    int32_t readPosition(); 
    int32_t writePosition(); 

    int avaibleSize(); 
    int isEmpty(); 
    void empty(); 
    int isFull(); 



private: 
    SharedMemoryAttributes *_attributes; 
    int32_t _writePosition; 
    int32_t _readPosition; 
    int32_t _length; 
    QSharedMemory *_sharedMemory; 
    int _headSize; 
signals: 
    void readFrame(QString name); 
public slots: 
}; 

#endif // SHAREDMEMORYRINGBUFFER_H 

而CPP文件:

#include "sharedmemoryringbuffer.h" 
#include <QDebug> 
#define DEBUGGINGNAME "[SharedMemoryRingbuffer]" 

SharedMemoryRingBuffer::SharedMemoryRingBuffer(QString sharedMemoryName, int32_t size, QObject *parent) : QObject(parent) 
{ 
    int sizeOfData = sizeof(int32_t) * (size); 
    int sizeOfHeader = sizeof(SharedMemoryAttributes); 
    _sharedMemory = new QSharedMemory(sharedMemoryName); 

    if (!_sharedMemory->attach()) { 
     if (!_sharedMemory->create(sizeOfData+sizeOfHeader, QSharedMemory::ReadWrite)) { 
      qDebug() << DEBUGGINGNAME << "Could not create shared memory object, aborting ..."; 
      qDebug() << DEBUGGINGNAME << _sharedMemory->errorString(); 
      //TODO: exit call 
      return; 
     } 
    } 

    _sharedMemory->lock(); 
    _attributes = reinterpret_cast<SharedMemoryAttributes*>(_sharedMemory->data()); 
    _attributes->readPosition = 0; 
    _attributes->writePosition = 0; 
    _attributes->size = size + 1; 
    _attributes->data = (int32_t*) _sharedMemory->data() + sizeOfHeader; 
    _sharedMemory->unlock(); 
} 

SharedMemoryRingBuffer::~SharedMemoryRingBuffer() 
{ 
    _sharedMemory->detach(); 
    delete _sharedMemory; 
} 

int SharedMemoryRingBuffer::write(int32_t frame) 
{ 
    _sharedMemory->lock(); 
    if (!isFull()) { 
     _attributes->data[writePosition()] = frame; 
     if (writePosition() + 1 >= _attributes->size) _attributes->writePosition = 0; 
     else _attributes->writePosition += 1; 
     _sharedMemory->unlock(); 
     return 1; 
    } 
    _sharedMemory->unlock(); 
    return 0; 
} 


/** 
* @brief SharedMemoryRingBuffer::read 
* @return 
* if the buffer is empty this functions returns the last readable value 
* 
*/ 
int32_t SharedMemoryRingBuffer::read() 
{ 
    _sharedMemory->lock(); 
    int32_t frame = _attributes->data[readPosition()]; 
    if (readPosition() != writePosition()) { 
     if (readPosition() + 1 >= _attributes->size) _attributes->readPosition = 0; 
     else _attributes->readPosition += 1; 
     emit readFrame(_sharedMemory->key()); 
    } 
    _sharedMemory->unlock(); 
    return frame; 
} 

int32_t SharedMemoryRingBuffer::length() 
{ 
    if(readPosition() <= writePosition()) { 
     return writePosition() - readPosition(); 
    } else { 
     return readPosition() - writePosition(); 
    } 
} 

int32_t SharedMemoryRingBuffer::readPosition() 
{ 
    return _attributes->readPosition; 
} 

int32_t SharedMemoryRingBuffer::writePosition() 
{ 
    return _attributes->writePosition; 
} 

int SharedMemoryRingBuffer::avaibleSize() 
{ 
    return -1; 
} 

int SharedMemoryRingBuffer::isEmpty() 
{ 
    if (readPosition() == writePosition()) return 1; 
    else return 0; 
} 

void SharedMemoryRingBuffer::empty() 
{ 

} 

int SharedMemoryRingBuffer::isFull() 
{ 
    if ((writePosition() + 1) % _attributes->size == readPosition()) return 1; 
    else return 0; 
} 
+0

附註:我建議爲RAII您的MT鎖定在您的「寫入」功能中。例如:。 '_sharedMemory-> lock();'如果任何後續函數調用執行'throw',則鎖定不會被釋放。 – PaulMcKenzie

回答

0

所以我找到了一個非常明顯的解決方案。如果第二個進程連接到共享內存它不應該設置的頭部和尾部位置爲0

這是固定的代碼,效果很好:)

#include "sharedmemoryringbuffer.h" 
#include <QDebug> 
#define DEBUGGINGNAME "[SharedMemoryRingbuffer]" 

SharedMemoryRingBuffer::SharedMemoryRingBuffer(QString sharedMemoryName, int32_t size, QObject *parent) : QObject(parent) 
{ 
    int sizeOfData = sizeof(int32_t) * (size); 
    int sizeOfHeader = sizeof(SharedMemoryAttributes); 
    _sharedMemory = new QSharedMemory(sharedMemoryName); 

    if (_sharedMemory->isAttached()) _sharedMemory->detach(); 
    if (!_sharedMemory->attach()) { 
     _sharedMemory->lock(); 
     _attributes = reinterpret_cast<SharedMemoryAttributes*>(_sharedMemory->data()); 
     _attributes->readPosition = 0; 
     _attributes->writePosition = 0; 
     _attributes->size = size; 
     _sharedMemory->unlock(); 

     if (!_sharedMemory->create(sizeOfData+sizeOfHeader, QSharedMemory::ReadWrite)) { 
      qDebug() << DEBUGGINGNAME << "Could not create shared memory object, aborting ..."; 
      qDebug() << DEBUGGINGNAME << _sharedMemory->errorString(); 
      //TODO: exit call 
      return; 
     } 
    } 

    _attributes->data = (int32_t*) _sharedMemory->data() + sizeOfHeader; 

} 

SharedMemoryRingBuffer::~SharedMemoryRingBuffer() 
{ 
    _sharedMemory->detach(); 
    delete _sharedMemory; 
} 

int SharedMemoryRingBuffer::write(int32_t frame) 
{ 
    _sharedMemory->lock(); 
    if (!isFull()) { 
     _attributes->data[writePosition()] = frame; 
     if (writePosition() + 1 >= _attributes->size) _attributes->writePosition = 0; 
     else _attributes->writePosition += 1; 
     _sharedMemory->unlock(); 
     return 1; 
    } 
    _sharedMemory->unlock(); 
    return 0; 
} 


/** 
* @brief SharedMemoryRingBuffer::read 
* @return 
* if the buffer is empty this functions return the last readable value 
* 
*/ 
int32_t SharedMemoryRingBuffer::read() 
{ 
    _sharedMemory->lock(); 
    int32_t frame = _attributes->data[readPosition()]; 
    if (readPosition() != writePosition()) { 
     if (readPosition() + 1 >= _attributes->size) _attributes->readPosition = 0; 
     else _attributes->readPosition += 1; 
     emit readFrame(_sharedMemory->key()); 
    } 
    _sharedMemory->unlock(); 
    return frame; 
} 

int32_t SharedMemoryRingBuffer::length() 
{ 
    if(readPosition() <= writePosition()) { 
     return writePosition() - readPosition(); 
    } else { 
     return readPosition() - writePosition(); 
    } 
} 

int32_t SharedMemoryRingBuffer::readPosition() 
{ 
    return _attributes->readPosition; 
} 

int32_t SharedMemoryRingBuffer::writePosition() 
{ 
    return _attributes->writePosition; 
} 

int SharedMemoryRingBuffer::avaibleSize() 
{ 
    return -1; 
} 

int SharedMemoryRingBuffer::isEmpty() 
{ 
    if (readPosition() == writePosition()) return 1; 
    else return 0; 
} 

void SharedMemoryRingBuffer::empty() 
{ 

} 

int SharedMemoryRingBuffer::isFull() 
{ 
    if ((writePosition() + 1) % _attributes->size == readPosition()) return 1; 
    else return 0; 
} 
0

這個初始化:

_attributes->size = size + 1; 

看起來不正確,因爲你傳遞給_sharedMemory-大小>創建()僅爲大小元素分配足夠的「數據」空間,而不是大小+ 1.爲什麼+1是?

+0

爲了在isFull()函數中獲得正確的邊界,我使用了這個模運算。但正如我所說,緩衝區在一個生產者和消費者的一個過程中運作良好。當我將它們分成不同的進程時,第一個進程崩潰。 –