一种环形队列的C语言实现---RingBuffer

// 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
}

你可能感兴趣的:(Tools,Program,Theory)