C++ 环形缓冲区的实现

参考文章:http://blog.csdn.net/linyt/article/details/53355355

本文参考linux系统中 kfifo缓冲区实现.由于没有涉及到锁,在多线程环境下,只适用于 单生产者 + 单消费者 模型.

fifo_buffer.h

#ifndef FIFO_BUFFER_H_
#define FIFO_BUFFER_H_
#include <stdint.h>

class FifoBuffer
{
public:
    enum
    {
        enmDefaultBufferLen = 1024,
    };
public:
    FifoBuffer(const uint32_t size = enmDefaultBufferLen);
    ~FifoBuffer();
public:
    uint32_t Put(const char *buf, const uint32_t bufLen);
    uint32_t Get(char buf[], const uint32_t maxBufLen);
    uint32_t Size(){ return size; }
    uint32_t EmptySize();
    uint32_t UsedSize();
    const char *Buffer(){ return buffer; }
private:
    uint32_t Min(uint32_t left, uint32_t right){ return left > right ? right : left; }
private:
    uint32_t size;
    volatile uint32_t in;
    volatile uint32_t out;
    char *buffer;
};
#endif

fifo_buffer.cpp

#include <malloc.h>
#include <new>
#include <algorithm>
#include "fifo_buffer.h"

//////////////////////////////////////////////////////////////////////////
// when out < in
// |                                        |
// |----------------------------------------|
// 0       out|~~~~~~~~~~|in                size
//////////////////////////////////////////////////////////////////////////
// when out > in
// |                                        |
// |----------------------------------------|
// 0~~~~~~~|in        out|~~~~~~~~~~~~~~~~~~size
//////////////////////////////////////////////////////////////////////////

FifoBuffer::FifoBuffer(const uint32_t size /*= enmDefaultBufferLen*/) :in(0), out(0), size(0)
{
    buffer = new (std::nothrow) char[size];
    if (!buffer){ return; }
    memset(buffer, 0, size);
    this->size = size;
}

FifoBuffer::~FifoBuffer()
{
    if (buffer)
    {
        delete[] buffer;
    }
}

uint32_t FifoBuffer::Put(const char *buf, const uint32_t bufLen)
{
    uint32_t lengthToPut = Min(bufLen, EmptySize());
    /* first put the data starting from fifo->in to buffer end */
    uint32_t len = Min(lengthToPut, size - (in % size));
    memcpy(buffer + (in % size), buf, len);
    /* then put the rest (if any) at the beginning of the buffer */
    memcpy(buffer, buf + len, lengthToPut - len);
    in += lengthToPut;
    return lengthToPut;
}

uint32_t FifoBuffer::Get(char buf[], const uint32_t maxBufLen)
{
    uint32_t lengthToGet = Min(maxBufLen, UsedSize());
    /* first get the data from fifo->out until the end of the buffer */
    uint32_t len = Min(lengthToGet, size - (out % size));
    memcpy(buf, buffer + (out % size), len);
    /* then get the rest (if any) from the beginning of the buffer */
    memcpy(buf + len, buffer, lengthToGet - len);
    out += lengthToGet;
    return lengthToGet;
}

uint32_t FifoBuffer::EmptySize()
{
    return size - in + out;
}

uint32_t FifoBuffer::UsedSize()
{
    return in - out;
}

测试代码:

#include <stdio.h>
#include <fstream>
#include <windows.h>
#include <thread>

#include "fifo_buffer.h"
const char *fileName = "data.txt";
enum 
{
    enummaxBufLen = 10243,
};

void WriteToFile(const char *fileName, const char *buf, const uint32_t bufLen);
void ReadFromFile(const char *fileName, char buf[], const uint32_t maxBufLen);
void GenTestFile();

void PutSomeBytes(const char *oriBuf, const uint32_t bufLen, FifoBuffer &fifoBuf);
void GetSomeBytes(FifoBuffer &fifoBuf, char buf[], const uint32_t maxBufLen);

int32_t main()
{
    GenTestFile();
    FifoBuffer fifoBuf(enummaxBufLen + 1);
    char *oriBuf = new char[enummaxBufLen + 1];
    char *putBuf = new char[enummaxBufLen + 1];
    memset(oriBuf, 0, enummaxBufLen + 1);
    memset(putBuf, 0, enummaxBufLen + 1);
    ReadFromFile(fileName, oriBuf, enummaxBufLen);
    //////////////////////////////////////////////////////////////////////////
    std::thread put(PutSomeBytes, oriBuf, enummaxBufLen, std::ref(fifoBuf));

    std::thread get(GetSomeBytes, std::ref(fifoBuf), putBuf, enummaxBufLen);

    put.join();
    get.join();

    printf("%s
%d

", fifoBuf.Buffer(), strlen(fifoBuf.Buffer()));

    printf("%s
%d

", putBuf, strlen(putBuf));
    system("pause");
}

void WriteToFile(const char *fileName, const char *buf, const uint32_t bufLen)
{
    std::ofstream outFile(fileName, std::ios::out);
    if (!outFile){ return; }
    outFile.write(buf, bufLen);
    outFile.close();
}

void ReadFromFile(const char *fileName, char buf[], const uint32_t maxBufLen)
{
    std::ifstream inFile(fileName, std::ios::in);
    if (!inFile){ return; }
    inFile.read(buf, maxBufLen);
    inFile.close();
}

void GenTestFile()
{
    char *buf = new char[enummaxBufLen];
    for (uint32_t i = 0; i < enummaxBufLen; ++i)
    {
        buf[i] = i % 10 + '0';
    }
    WriteToFile(fileName, buf, enummaxBufLen);
    delete[] buf;
}

void PutSomeBytes(const char *oriBuf, const uint32_t bufLen, FifoBuffer &fifoBuf)
{
    static uint32_t offset = 0;
    while (offset < bufLen)
    {
        int32_t byteCount = rand() % 3;
        offset += fifoBuf.Put(oriBuf + offset, byteCount);
        Sleep(1);
    }
}

void GetSomeBytes(FifoBuffer &fifoBuf, char buf[], const uint32_t maxBufLen)
{
    static uint32_t offset = 0;
    while (offset < maxBufLen)
    {
        int32_t byteCount = rand() % 3;
        offset += fifoBuf.Get(buf + offset, byteCount);
    }
}
原文地址:https://www.cnblogs.com/tangxin-blog/p/6131952.html