简单实用的环形缓冲器
近来处理音频rawdata时需要一个FIFO的内存缓冲,自己写了一个基于环形结构的缓冲器。
- 可处理任意大小输入,输出
- 数据不够时可强制获取剩余数据
- 代码极简
- 线程安全
bug可能有,暂时没发现。
/*
* CREATE: tifentan
* DATE: 2017/8/23
* MODIFY: 2017/8/23
* NOTE:
*
*
*/
#ifndef __CIRCLEBUFFER_H__
#define __CIRCLEBUFFER_H__
#include <pthread.h>
class CircleBuffer
{
public:
//请输入正数
CircleBuffer(int len);
~CircleBuffer();
void clear();
//返回size
int push_data(char* src,int len);
//force 强行不够指定的len也拿出来,有多少拿多少
//outlen 返回实际取出的大小
//返回size, -1代表参数出错
int pop_data(char* dst,int len,int* outlen,bool force = 0);
int size();
public:
pthread_mutex_t data_mtx_;
char *p_buf_;
int len_; //总长度
int size_; //有效长度
private:
char* ptr_w_; //写指针
char* ptr_r_; //读指针
int diff_to_end_w_;
int diff_to_end_r_;
};
#endif
/*
* CREATE: tifentan
* DATE: 2017/8/23
* MODIFY: 2017/8/23
* NOTE:
*
*
*/
#include "circlebuffer.h"
#include <android/log.h>
#define ANDROID_LOG_MSG(...) __android_log_print(ANDROID_LOG_INFO, __VA_ARGS__)
CircleBuffer::CircleBuffer(int len):
len_(len),
size_(0),
diff_to_end_w_(len),
diff_to_end_r_(len)
{
pthread_mutex_init(&data_mtx_, NULL);
p_buf_ = (char*)malloc(len);
ptr_w_ = ptr_r_ = p_buf_;
}
CircleBuffer::~CircleBuffer()
{
free(p_buf_);
}
void CircleBuffer::clear()
{
pthread_mutex_lock(&data_mtx_);
ptr_w_ = ptr_r_ = p_buf_;
size_ = 0;
diff_to_end_w_ = diff_to_end_r_ = len_;
pthread_mutex_unlock(&data_mtx_);
}
int CircleBuffer::push_data(char * src, int len)
{
if (src == 0 || len <= 0)
return 0;
int endsize = 0;
int oversize = 0;
int loopsize = 0;
//当输入的src比总长度还长,保留src后面len_大小的内存,前面的丢弃
if (len > len_) {
src = src + len - len_;
len = len_;
}
pthread_mutex_lock(&data_mtx_);
oversize = len + size_ - len_;
loopsize = len - diff_to_end_w_;
//loop back
if (loopsize > 0) {
memcpy(ptr_w_, src, diff_to_end_w_);
memcpy(p_buf_, src + diff_to_end_w_, loopsize);
ptr_w_ = p_buf_ + loopsize;
diff_to_end_w_ = len_ - loopsize;
}
else {
memcpy(ptr_w_, src, len);
if (loopsize == 0) { //刚好到p_buf_最后
ptr_w_ = p_buf_;
diff_to_end_w_ = len_;
}else {
ptr_w_ += len;
diff_to_end_w_ -= len;
}
}
//满了,覆盖旧的
if (oversize > 0) {
size_ = len_;
ptr_r_ = ptr_w_;
diff_to_end_r_ = diff_to_end_w_;
ANDROID_LOG_MSG("CircleBuffer", "buffer full!! overwrite[%d]", oversize);
}else {
size_ += len;
}
endsize = size_;
pthread_mutex_unlock(&data_mtx_);
return endsize;
}
int CircleBuffer::pop_data(char * dst, int len, int* outlen, bool force)
{
if (dst == 0 || len <= 0 || outlen == 0) {
return -1;
}
int endsize = 0;
int loopsize = 0;
pthread_mutex_lock(&data_mtx_);
if (len > size_) {
if (force) {
len = size_;
}else {
*outlen = 0;
goto END;
}
}
*outlen = len;
loopsize = len - diff_to_end_r_;
//loop back
if (loopsize > 0) {
memcpy(dst, ptr_r_, diff_to_end_r_);
memcpy(dst + diff_to_end_r_,p_buf_, loopsize);
ptr_r_ = p_buf_ + loopsize;
diff_to_end_r_ = len_ - loopsize;
}
else {
memcpy(dst, ptr_r_, len);
if (loopsize == 0) {
ptr_r_ = p_buf_;
diff_to_end_r_ = len_;
}else {
ptr_r_ += len;
diff_to_end_r_ -= len;
}
}
size_ -= len;
END:
endsize = size_;
pthread_mutex_unlock(&data_mtx_);
return endsize;
}
int CircleBuffer::size()
{
int endsize = 0;
//多数平台支持int的原子操作下,不用锁应该没问题
//pthread_mutex_lock(&data_mtx_);
endsize = size_;
//pthread_mutex_unlock(&data_mtx_);
return endsize;
}