简单的双缓冲区实现
一、简述
在一些应用中可能需要用到双缓冲区,每个缓冲区有两种状态——可读的和可写的。当可写的缓冲区写满后转变为可读的,当可读的缓冲区数据全部被读取后转变为可写的。
二、实现
实现中使用了线程互斥量,保证各个操作是线程安全的。
/* 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 */