参考文章: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\n%d\n\n", fifoBuf.Buffer(), strlen(fifoBuf.Buffer())); printf("%s\n%d\n\n", 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); } }