共享内存环形缓冲区崩溃

Shared memory ring buffer crashes

我用 QT 编写了一个共享内存环形缓冲区,结果证明它在一个消费者和一个写入者的单个进程中运行良好。如果我尝试从第二个进程读取数据,我第一个连接的进程会因段错误而崩溃。也许我忽略了什么?

头文件

#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;
}

本次初始化:

_attributes->size = size + 1;

看起来不正确,因为您传递给 _sharedMemory->create() 的大小仅分配足够的 "data" space 用于 size 元素,而不是 size + 1。为什么 +1 在那里?

所以我找到了一个非常明显的解决方案。如果第二个进程连接到共享内存,则不应将头尾位置设置为 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;
}