// RingBuffer.h
#ifndef __RINGBUFFER_H__
#define __RINGBUFFER_H__
// 如果要使用在C++中 则使用该宏定义片段
// #ifdef __cplusplus
// extern "C"
// {
// #endif
#include
#include
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef struct _RingBuffer {
u8* mBuffer;
u32 font;
u32 tail;
u16 bWriteClosed;
u16 bReadClosed;
int bufferSize;
pthread_cond_t mReadVariableCond;
pthread_cond_t mWriteVariableCond;
pthread_mutex_t mMutex;
}RingBuffer;
RingBuffer* CreateRingBuffer(int bufferSize);
void DestroyRingBuffer(RingBuffer *pRB);
int RingBuffer_Read(RingBuffer *pRB, void *data, size_t len, int timeout);
int RingBuffer_Write(RingBuffer *pRB, void *data, size_t len, int timeout);
void RingBuffer_SetRead(RingBuffer *pRB, int bClosed);
void RingBuffer_SetWrite(RingBuffer *pRB, int bClosed);
void RingBuffer_Reset(RingBuffer *pRB);
// 如果要使用在C++中 则使用该宏定义片段
// #ifdef __cplusplus
// }
// #endif
#endif
// RingBuffer.c
#include "RingBuffer.h"
#include
#include
#include
#include
#include
#include
/******************************************************************************************************************
Function:
CreateRingBuffer
Paramters:
bufferSize : 环形Buffer的大小
ReturnValue:
返回构造好的RingBuffer指针;
失败则返回 NULL;
******************************************************************************************************************/
RingBuffer* CreateRingBuffer(int bufferSize) {
RingBuffer *pTmpRingBuffer = NULL;
pTmpRingBuffer = (RingBuffer*)malloc(sizeof(RingBuffer));
if (pTmpRingBuffer == NULL) {
return NULL;
}
// memset after malloc
memset((void*)pTmpRingBuffer, 0, sizeof(RingBuffer));
pTmpRingBuffer->mBuffer = (u8*)malloc(bufferSize);
if (pTmpRingBuffer->mBuffer == NULL) {
free(pTmpRingBuffer);
return NULL;
}
memset((void*)pTmpRingBuffer->mBuffer, 0, bufferSize);
pTmpRingBuffer->bufferSize = bufferSize;
pTmpRingBuffer->font = pTmpRingBuffer->tail = 0;
// init mutext
pthread_mutex_init(&pTmpRingBuffer->mMutex, NULL);
// init condition
#ifdef _IOS_
pTmpRingBuffer->mReadVariableCond = PTHREAD_COND_INITIALIZER;
pTmpRingBuffer->mWriteVariableCond = PTHREAD_COND_INITIALIZER;
#elif _ANDROID_
#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
pTmpRingBuffer->mReadVariableCond = PTHREAD_COND_INITIALIZER;
pTmpRingBuffer->mWriteVariableCond = PTHREAD_COND_INITIALIZER;
#else
// pthread_condattr_t cattr;
// pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
// pthread_cond_init(&pTmpRingBuffer->mReadVariableCond, &cattr);
// pthread_cond_init(&pTmpRingBuffer->mWriteVariableCond, &cattr);
pTmpRingBuffer->mReadVariableCond = PTHREAD_COND_INITIALIZER;
pTmpRingBuffer->mWriteVariableCond = PTHREAD_COND_INITIALIZER;
#endif
#else // Linux
pthread_condattr_t cattr;
pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
pthread_cond_init(&pTmpRingBuffer->mReadVariableCond, &cattr);
pthread_cond_init(&pTmpRingBuffer->mWriteVariableCond, &cattr);
#endif
return pTmpRingBuffer;
}
/******************************************************************************************************************
Function:
DestroyRingBuffer
Paramters:
pRB : RingBuffer的指针
ReturnValue:
void
******************************************************************************************************************/
void DestroyRingBuffer(RingBuffer *pRB) {
pRB->bReadClosed = 1;
pRB->bWriteClosed = 1;
usleep(300*1000);
pthread_mutex_destroy(&pRB->mMutex);
pthread_cond_destroy(&pRB->mReadVariableCond);
pthread_cond_destroy(&pRB->mWriteVariableCond);
free(pRB->mBuffer);
free(pRB);
}
/******************************************************************************************************************
Function:
RingBufferDataSize
Paramters:
pRB : RingBuffer的指针
ReturnValue:
返回当前RingBuffer中实际有效数据的字节数
******************************************************************************************************************/
static inline size_t RingBufferDataSize(RingBuffer *pRB) {
return (pRB->tail - pRB->font + pRB->bufferSize) % pRB->bufferSize;
}
/******************************************************************************************************************
Function:
RingBufferFreeSize
Paramters:
pRB : RingBuffer的指针
ReturnValue:
返回当前RingBuffer中空闲空间的字节数
******************************************************************************************************************/
static inline size_t RingBufferFreeSize(RingBuffer *pRB) {
return ((pRB->bufferSize-1) - ((pRB->tail - pRB->font + pRB->bufferSize) % pRB->bufferSize));
}
/******************************************************************************************************************
Function:
RingBufferIsEmpty
Paramters:
pRB : RingBuffer的指针
ReturnValue:
返回当前RingBuffer是否为空
!= 0 为空
== 0 不为空
******************************************************************************************************************/
static inline int RingBufferIsEmpty(RingBuffer *pRB) {
return (pRB->font == pRB->tail);
}
/******************************************************************************************************************
Function:
RingBufferIsFull
Paramters:
pRB : RingBuffer的指针
ReturnValue:
返回当前RingBuffer是否已满
!= 0 已满
== 0 未满
******************************************************************************************************************/
static inline int RingBufferIsFull(RingBuffer *pRB) {
return (((pRB->tail+1)%pRB->bufferSize) == pRB->font);
}
/******************************************************************************************************************
Function:
preRead
Paramters:
pRB : RingBuffer的指针
ReturnValue:
预判RingBuffer是否可读
当RingBuffer可读 且 当前为空的情况 返回 非零, 否则返回零
******************************************************************************************************************/
static inline int preRead(RingBuffer *pRB) {
return ((!pRB->bReadClosed) && (RingBufferIsEmpty(pRB)));
}
/******************************************************************************************************************
Function:
preWrite
Paramters:
pRB : RingBuffer的指针
ReturnValue:
预判RingBuffer是否可写
当RingBuffer可读 且 当前为满的情况 返回 非零, 否则返回零
******************************************************************************************************************/
static inline int preWrite(RingBuffer *pRB) {
return ((!pRB->bWriteClosed) && (RingBufferIsFull(pRB)));
}
/******************************************************************************************************************
Function:
RingBuffer_Read
Paramters:
pRB : RingBuffer的指针
data : 读取的数据返回的临时缓冲区
len : 需要读取的数据字节数
timeout : 等待策略&超时时间
= 0 : 一直等待直到有数据可读 或者 读操作被中止
= -1 : 不等待 无论是否有数据 都直接返回
> 0 : 超时等待时间 单位为毫秒 ms
ReturnValue:
= -3 : 未知错误
= -2 : 读操作被中止
= -1 : 读数据等待超时
>= 0 : 实际读取的数据字节数
******************************************************************************************************************/
int RingBuffer_Read(RingBuffer *pRB, void *data, size_t len, int timeout) {
int ret = 0;
pthread_mutex_lock(&pRB->mMutex); // 获取锁
if (timeout == 0) {
while (preRead(pRB)) { // 一直等待有数据进入 或者 手动结束
pthread_cond_wait(&pRB->mReadVariableCond, &pRB->mMutex);
}
} else if (timeout > 0) {
#ifdef _IOS_
struct timespec tv;
clock_gettime(_CLOCK_MONOTONIC, &tv);
tv.tv_sec += timeout/1000;
tv.tv_nsec += (timeout % 1000) * 1000000;
while (preRead(pRB)) {
if (pthread_cond_timedwait(&pRB->mReadVariableCond, &pRB->mMutex, &tv)) {
ret = -1;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
}
#elif _ANDROID_
// ============================================================================================
#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
tv.tv_sec += timeout/1000;
tv.tv_nsec += (timeout % 1000) * 1000000;
while (preRead(pRB)) {
if (pthread_cond_timedwait_monotonic(&pRB->mReadVariableCond, &pRB->mMutex, &tv)) {
ret = -1;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
}
#else
struct timeval now;
struct timespec outtime;
gettimeofday(&now, NULL);
outtime.tv_sec = now.tv_sec + timeout/1000;
outtime.tv_nsec = (now.tv_usec + timeout*1000)*1000;
while (preRead(pRB)) {
if (pthread_cond_timedwait(&pRB->mReadVariableCond, &pRB->mMutex, &outtime)) {
ret = -1;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
}
#endif
// ============================================================================================
#else
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
tv.tv_sec += timeout/1000;
tv.tv_nsec += (timeout % 1000) * 1000000;
while (preRead(pRB)) {
if (pthread_cond_timedwait(&pRB->mReadVariableCond, &pRB->mMutex, &tv)) {
ret = -1;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
}
#endif
} else if (timeout < -1) {
printf("invalid timeout value = %d \r\n", timeout);
ret = -3;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
if (pRB->bReadClosed) { // 手动结束 不执行数据读操作
ret = -2;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
size_t bufferSize = RingBufferDataSize(pRB);
u32 CurPos = 0;
size_t needReadLen = 0;
u8 *pData = NULL;
size_t ResSafeLen = 0;
if (bufferSize == 0) { // 不等待 有数据就读取 无数据就直接返回
ret = 0;
} if (bufferSize < len) { // 队列内的数据长度 < 需要读取的长度 直接返回队列中的所有数据
CurPos = (pRB->font+1)%pRB->bufferSize;
needReadLen = bufferSize;
ResSafeLen = pRB->bufferSize - CurPos;
if (needReadLen <= ResSafeLen) {
memcpy((void*)data, (void*)&pRB->mBuffer[(pRB->font+1)%pRB->bufferSize], needReadLen);
pRB->font = (pRB->font + needReadLen) % pRB->bufferSize;
ret = needReadLen;
} else {
memcpy((void*)data, (void*)&pRB->mBuffer[(pRB->font+1)%pRB->bufferSize], ResSafeLen);
pRB->font = (pRB->font + ResSafeLen) % pRB->bufferSize;
pData = (u8*)data;
pData += ResSafeLen;
memcpy((void*)pData, (void*)&pRB->mBuffer[(pRB->font+1)%pRB->bufferSize], (needReadLen - ResSafeLen));
pRB->font = (pRB->font + (needReadLen - ResSafeLen)) % pRB->bufferSize;
ret = needReadLen;
}
} else { // 队列内的数据长度 >= 需要读取的长度 返回需要读取长度的数据
CurPos = (pRB->font+1)%pRB->bufferSize;
needReadLen = len;
ResSafeLen = pRB->bufferSize - CurPos;
if (needReadLen <= ResSafeLen) {
memcpy((void*)data, (void*)&pRB->mBuffer[(pRB->font+1)%pRB->bufferSize], needReadLen);
pRB->font = (pRB->font + needReadLen) % pRB->bufferSize;
ret = needReadLen;
} else {
memcpy((void*)data, (void*)&pRB->mBuffer[(pRB->font+1)%pRB->bufferSize], ResSafeLen);
pRB->font = (pRB->font + ResSafeLen) % pRB->bufferSize;
pData = (u8*)data;
pData += ResSafeLen;
memcpy((void*)pData, (void*)&pRB->mBuffer[(pRB->font+1)%pRB->bufferSize], (needReadLen - ResSafeLen));
pRB->font = (pRB->font + (needReadLen - ResSafeLen)) % pRB->bufferSize;
ret = needReadLen;
}
}
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
if(ret >= 0) { // 通知出去 可以写啦
pthread_cond_broadcast(&pRB->mWriteVariableCond);
}
return ret;
}
/******************************************************************************************************************
Function:
RingBuffer_Write
Paramters:
pRB : RingBuffer的指针
data : 写入的数据存放的临时缓冲区
len : 需要写入的数据字节数
timeout : 等待策略&超时时间
= 0 : 一直等待直到有空间可写 或者 写操作被中止
= -1 : 不等待 无论是否有空间 都直接返回
> 0 : 超时等待时间 单位为毫秒 ms
ReturnValue:
= -3 : 未知错误
= -2 : 写操作被中止
= -1 : 写数据等待超时
>= 0 : 实际写入的数据字节数
******************************************************************************************************************/
int RingBuffer_Write(RingBuffer *pRB, void *data, size_t len, int timeout) {
int ret = 0;
pthread_mutex_lock(&pRB->mMutex); // 获取锁
if (timeout == 0) {
while (preWrite(pRB)) { // 一直等待可以有空间可以写入 或者 手动结束
pthread_cond_wait(&pRB->mWriteVariableCond, &pRB->mMutex);
}
} else if (timeout > 0) {
#ifdef _IOS_
struct timespec tv;
clock_gettime(_CLOCK_MONOTONIC, &tv);
tv.tv_sec += timeout/1000;
tv.tv_nsec += (timeout % 1000) * 1000000;
while (preWrite(pRB)) {
printf("write ..... \r\n");
if (pthread_cond_timedwait(&pRB->mWriteVariableCond, &pRB->mMutex, &tv)) {
ret = -1;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
}
#elif _ANDROID_
// ============================================================================================
#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
tv.tv_sec += timeout/1000;
tv.tv_nsec += (timeout % 1000) * 1000000;
while (preWrite(pRB)) {
if (pthread_cond_timedwait_monotonic(&pRB->mReadVariableCond, &pRB->mMutex, &tv)) {
ret = -1;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
}
#else
struct timeval now;
struct timespec outtime;
gettimeofday(&now, NULL);
outtime.tv_sec = now.tv_sec + timeout/1000;
outtime.tv_nsec = (now.tv_usec + timeout*1000)*1000;
while (preWrite(pRB)) {
if (pthread_cond_timedwait(&pRB->mReadVariableCond, &pRB->mMutex, &outtime)) {
ret = -1;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
}
#endif
// ============================================================================================
#else
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
tv.tv_sec += timeout/1000;
tv.tv_nsec += (timeout % 1000) * 1000000;
while (preWrite(pRB)) {
printf("write ..... \r\n");
if (pthread_cond_timedwait(&pRB->mWriteVariableCond, &pRB->mMutex, &tv)) {
ret = -1;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
}
#endif
} else if (timeout < -1) {
printf("invalid timeout value = %d \r\n", timeout);
ret = -3;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
if (pRB->bWriteClosed) { // 手动结束 不执行数据写操作
ret = -2;
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
return ret;
}
size_t bufferSize = RingBufferFreeSize(pRB);
u32 CurPos = 0;
size_t needWriteLen = 0;
u8 *pData = NULL;
size_t ResSafeLen = 0;
if (bufferSize == 0) { // 不等待 有空闲空间就写 没有空闲空间就直接返回
ret = 0;
} if (bufferSize < len) { // 空闲空间 < 实际需要写入的空间 就写入空闲空间长度的数据
CurPos = (pRB->tail+1)%pRB->bufferSize;
needWriteLen = bufferSize;
ResSafeLen = pRB->bufferSize - CurPos; // 计算当前位置到数组尾部还剩余的有效长度, 因为超过尾部是需要重新调头到数组开始的位置的
if (needWriteLen <= ResSafeLen) { // 如果需要写入的长度在数组剩余安全长度以内 则直接写入到数组尾部
memcpy((void*)&pRB->mBuffer[(pRB->tail+1)%pRB->bufferSize], (void*)data, needWriteLen);
pRB->tail = (pRB->tail + needWriteLen) % pRB->bufferSize;
ret = needWriteLen;
} else {
memcpy((void*)&pRB->mBuffer[(pRB->tail+1)%pRB->bufferSize], (void*)data, ResSafeLen);
pRB->tail = (pRB->tail + ResSafeLen) % pRB->bufferSize;
pData = (u8*)data;
pData += ResSafeLen;
memcpy((void*)&pRB->mBuffer[(pRB->tail+1)%pRB->bufferSize], (void*)pData, (needWriteLen - ResSafeLen));
pRB->tail = (pRB->tail + (needWriteLen - ResSafeLen)) % pRB->bufferSize;
ret = needWriteLen;
}
} else { // 空闲空间 >= 实际需要写入的空间 就全部写入数据
CurPos = (pRB->tail+1)%pRB->bufferSize;
needWriteLen = len;
ResSafeLen = pRB->bufferSize - CurPos;
if (needWriteLen < ResSafeLen) {
memcpy((void*)&pRB->mBuffer[(pRB->tail+1)%pRB->bufferSize], (void*)data, needWriteLen);
pRB->tail = (pRB->tail + needWriteLen) % pRB->bufferSize;
ret = needWriteLen;
} else {
memcpy((void*)&pRB->mBuffer[(pRB->tail+1)%pRB->bufferSize], (void*)data, ResSafeLen);
pRB->tail = (pRB->tail + ResSafeLen) % pRB->bufferSize;
pData = (u8*)data;
pData += ResSafeLen;
memcpy((void*)&pRB->mBuffer[(pRB->tail+1)%pRB->bufferSize], (void*)pData, (needWriteLen - ResSafeLen));
pRB->tail = (pRB->tail + (needWriteLen - ResSafeLen)) % pRB->bufferSize;
ret = needWriteLen;
}
}
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
if(ret >= 0) { // 通知出去 可以读啦
pthread_cond_broadcast(&pRB->mReadVariableCond);
}
return ret;
}
/******************************************************************************************************************
Function:
RingBuffer_SetRead
Paramters:
pRB : RingBuffer的指针
bClosed : 是否关闭
ReturnValue:
void
******************************************************************************************************************/
void RingBuffer_SetRead(RingBuffer *pRB, int bClosed) {
pRB->bReadClosed = bClosed;
}
/******************************************************************************************************************
Function:
RingBuffer_SetWrite
Paramters:
pRB : RingBuffer的指针
bClosed : 是否关闭
ReturnValue:
void
******************************************************************************************************************/
void RingBuffer_SetWrite(RingBuffer *pRB, int bClosed) {
pRB->bWriteClosed = bClosed;
}
/******************************************************************************************************************
Function:
RingBuffer_Reset
Paramters:
pRB : RingBuffer的指针
ReturnValue:
void
******************************************************************************************************************/
void RingBuffer_Reset(RingBuffer *pRB) {
#ifdef _IOS_
pthread_mutex_lock(&pRB->mMutex); // 获取锁
#endif
pRB->font = 0;
pRB->tail = 0;
pRB->bReadClosed = 1;
pRB->bWriteClosed = 1;
#ifdef _IOS_
pthread_mutex_unlock(&pRB->mMutex); // 释放锁
#endif
}