天天看点

简单的双缓冲区实现简单的双缓冲区实现

简单的双缓冲区实现

一、简述

在一些应用中可能需要用到双缓冲区,每个缓冲区有两种状态——可读的和可写的。当可写的缓冲区写满后转变为可读的,当可读的缓冲区数据全部被读取后转变为可写的。

二、实现

实现中使用了线程互斥量,保证各个操作是线程安全的。

/* doublebuffer.h starting */
#ifndef __DOUBLE_BUFFER_H__
#define __DOUBLE_BUFFER_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#ifndef NULL
	#define NULL	((void *)0)
#endif

#ifndef FAIL
	#define FAIL	(-1)
#endif

#ifndef SUCC
	#define SUCC	(0)
#endif

#ifndef TRUE
	#define TRUE	(1)
#endif

#ifndef FALSE
	#define FALSE	(0)
#endif

#define DOUBLE_BUF_NORMAL
#define DOUBLE_BUF_DEBUG
#define DOUBLE_BUF_ERROR
#define DOUBLE_BUF_ASSERT

#ifdef DOUBLE_BUF_NORMAL
	#define nprintf(fmt, args...)\
	do {\
		fprintf(stderr, fmt, ##args);\
	} while(0)
#else
	#define nprintf(fmt, args...)	NULL
#endif

#ifdef DOUBLE_BUF_DEBUG
	#define dprintf(fmt, args...)\
	do {\
		fprintf(stderr, "[D] "fmt, ##args);\
	} while(0)
#else
	#define dprintf(fmt, args...)	NULL
#endif

#ifdef DOUBLE_BUF_ERROR
	#define eprintf(fmt, args...)\
	do {\
		fprintf(stderr, "[E] "fmt, ##args);\
	} while(0)
#else
	#define eprintf(fmt, args...)	NULL
#endif

#ifdef DOUBLE_BUF_ASSERT
	#define dbassert(cond)\
		if(cond)\
			NULL;\
		else\
			fflush(stdout),\
			fflush(stderr),\
			fprintf(stderr, "Assertion failed: expr[%s], file[%s], func[%s], line[%u]\n",\
					#cond, __FILE__, __func__, __LINE__),\
			fflush(stderr),\
			abort()
#else
	#define	dbassert(cond)		NULL
#endif

typedef struct buf {
	void *pdata;
	int index;
	int status;
	int size;
}buf_t;

typedef struct double_buf {
	buf_t buf[2];
	pthread_mutex_t mutex;
}double_buf_t;

enum double_buf_status {
	WRITABLE = 0,
	READABLE,
	DEAD,
};

/**
 * @创建一个双缓冲区
 * @db: 双缓冲结构体指针
 * @size: 每个缓冲区的大小
 * @return SUCC/FAIL
 */
int create_double_buf(double_buf_t *db, int size);

/**
 * @销毁一个双缓冲区
 */
void destroy_double_buf(double_buf_t *db);

/**
 * @往双缓冲中写数据
 * @db: 双缓冲结构体指针
 * @wdata: 数据指针
 * @size: 数据大小
 * @return SUCC/FAIL
 */
int write_double_buf(double_buf_t *db, void *wdata, int size);

/**
 * @往双缓冲中写数据
 * @db: 双缓冲结构体指针
 * @wdata: 数据指针
 * @size: 数据大小
 * @return SUCC
 * @如果两个缓冲区都满了将覆盖第一个缓冲区
 */
int write_double_buf_cover(double_buf_t *db, void *wdata, int size);

/**
 * @从双缓冲中读数据
 * @db: 双缓冲结构体指针
 * @rdata: 数据指针
 * @size: 数据大小
 * @return SUCC/FAIL
 */
int read_double_buf(double_buf_t *db, void *rdata, int size);

#ifdef __cplusplus
}
#endif

#endif
/* doublebuffer.h ending */
           
/* doublebuffer.c starting */
#include "doublebuffer.h"
#include <memory.h>

static inline void __lock_double_buf(pthread_mutex_t *mutex)
{
	pthread_mutex_lock(mutex);
}

static inline void lock_double_buf(double_buf_t *db)
{
	__lock_double_buf(&db->mutex);
}

static inline void __unlock_double_buf(pthread_mutex_t *mutex)
{
	pthread_mutex_unlock(mutex);
}

static inline void unlock_double_buf(double_buf_t *db)
{
	__unlock_double_buf(&db->mutex);
}

/**
 * @找到一个可写缓冲区
 * @return 缓冲区编号/FAIL
 */
static int find_writable_buf(double_buf_t *db, int size)
{
	int i;
	
	for(i=0; i<2; i++)
	{
		if(db->buf[i].status==WRITABLE
		   && (db->buf[i].index+size)<=db->buf[i].size)
		   return i;
	}
	
	return FAIL;
}

/**
 * @找到一个可读缓冲区
 * @return 缓冲区编号/FAIL
 */
static int find_readable_buf(double_buf_t *db, int size)
{
	int i;
	
	for(i=0; i<2; i++)
	{
		if(db->buf[i].status==READABLE
		   && db->buf[i].index>=size)
		   return i;
	}
	
	return FAIL;
}

static void __write_double_buf(double_buf_t *db, int n, void *wdata, int size)
{
	int index = db->buf[n].index;
	
	memcpy(db->buf[n].pdata+index, wdata, size);
	db->buf[n].index += size;
	if(db->buf[n].index >= db->buf[n].size)
		db->buf[n].status = READABLE;
}

static int __read_double_buf(double_buf_t *db, int n, void *rdata, int size)
{
	static int rindex = 0;
	
	if(rindex + size > db->buf[n].size)
		return FAIL;
	
	memcpy(rdata, db->buf[n].pdata+rindex, size);
	rindex += size;
	if(rindex >= db->buf[n].size)
	{
		rindex = 0;
		db->buf[n].index = 0;
		db->buf[n].status = WRITABLE;
	}
	
	return SUCC;
}

/**
 * @创建一个双缓冲区
 * @db: 双缓冲结构体指针
 * @size: 每个缓冲区的大小
 * @return SUCC/FAIL
 */
int create_double_buf(double_buf_t *db, int size)
{
	int i;
	
	dbassert(db);
	dbassert(size > 0);
	
	db->buf[0].pdata = (void *)malloc(size);
	if(!db->buf[0].pdata)
		return FAIL;
	
	db->buf[1].pdata = (void *)malloc(size);
	if(!db->buf[1].pdata)
	{
		free(db->buf[0].pdata);
		return FAIL;
	}
	
	for(i=0; i<2; i++)	
	{
		db->buf[i].index = 0;
		db->buf[i].status = WRITABLE;
		db->buf[i].size = size;
	}
	
	pthread_mutex_init(&db->mutex, NULL);
	
	return SUCC;
}

/**
 * @销毁一个双缓冲区
 */
void destroy_double_buf(double_buf_t *db)
{
	int i;
	
	dbassert(db);
		
	lock_double_buf(db);
	for(i=0; i<2; i++)
	{
		free(db->buf[i].pdata);
		db->buf[i].status = DEAD;
		db->buf[i].index = 0;
	}
	unlock_double_buf(db);
}

/**
 * @往双缓冲中写数据
 * @db: 双缓冲结构体指针
 * @wdata: 数据指针
 * @size: 数据大小
 * @return SUCC/FAIL
 */
int write_double_buf(double_buf_t *db, void *wdata, int size)
{
	int i;
	
	dbassert(db);
	dbassert(wdata);
	dbassert(size);
	
	lock_double_buf(db);
	i = find_writable_buf(db, size);
	if(i < 0)
	{
		unlock_double_buf(db);
		return FAIL;
	}
	
	__write_double_buf(db, i, wdata, size);
	unlock_double_buf(db);
	return SUCC;
}

/**
 * @往双缓冲中写数据
 * @db: 双缓冲结构体指针
 * @wdata: 数据指针
 * @size: 数据大小
 * @return SUCC
 * @如果两个缓冲区都满了将覆盖第一个缓冲区
 */
int write_double_buf_cover(double_buf_t *db, void *wdata, int size)
{
	int i;
	
	dbassert(db);
	dbassert(wdata);
	dbassert(size);
	
	lock_double_buf(db);
	i = find_writable_buf(db, size);
	if(i < 0)
	{
		i = 0;
		db->buf[i].status = WRITABLE;
		db->buf[i].index = 0;	
	}
	
	__write_double_buf(db, i, wdata, size);
	unlock_double_buf(db);
	return SUCC;
}

/**
 * @从双缓冲中读数据
 * @db: 双缓冲结构体指针
 * @rdata: 数据指针
 * @size: 数据大小
 * @return SUCC/FAIL
 */
int read_double_buf(double_buf_t *db, void *rdata, int size)
{
	int i;
	
	dbassert(db);
	dbassert(rdata);
	dbassert(size);
	
	lock_double_buf(db);
	i = find_readable_buf(db, size);
	if(i < 0)
	{
		unlock_double_buf(db);
		return FAIL;
	}
	
	i = __read_double_buf(db, i, rdata, size);
	if(i < 0)
	{
		unlock_double_buf(db);
		return FAIL;
	}
	
	unlock_double_buf(db);
	return SUCC;
}
/* doublebuffer.c ending */
           

继续阅读