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