1、背景
当一个服务端对外获取数据然后将自己获取的数据分发给客户端,但是在分发环节特别耗时导致外界向服务端请求去读,但是此时服务端并没有响应去读取外界数据,此时导致了外界请求端的缓存溢出,数据存在丢失的问题。
2、解决方式
这里的解决手段需要两步,第一提高服务端对外界的响应程度 (提高服务端线程的调度优先级),第二在服务端和分发的客户端端之间建立缓冲池。这里重点说缓冲池。
3、实际操作
这里介绍一个缓冲池(ringBuffer)的使用。
ringbuf.h
#ifndef _RINGBUFFER_H
#define _RINGBUFFER_H
struct ringbuffer {
void *data;
unsigned int size;
unsigned int read_pos;
unsigned int write_pos;
};
struct ringbuffer *ringbuffer_create(unsigned int bytes);
void ringbuffer_destroy(struct ringbuffer *ring_buf);
void ringbuffer_reset(struct ringbuffer *ring_buf);
unsigned int ringbuffer_put(struct ringbuffer *ring_buf,const char *buf, unsigned int len);
unsigned int ringbuffer_get(struct ringbuffer *ring_buf,char *buf, unsigned int len);
ssize_t ringbuffer_from_dev(int fd, struct ringbuffer *ring_buf, unsigned int len);
unsigned int ringbuffer_is_empty(struct ringbuffer *ring_buf);
unsigned int ringbuffer_is_full(struct ringbuffer *ring_buf);
unsigned int ringbuffer_len(struct ringbuffer *ring_buf);
unsigned int ringbuffer_space_left(struct ringbuffer *ring_buf);
#endif
ringbuf.c
struct ringbuffer* tmp_fifo;
//这里的 n 必须等于 为 2的次幂方
static inline __attribute__((const)) int is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
// 创建初始化 ringBuffer
struct ringbuffer *ringbuffer_create(unsigned int size)
{
struct ringbuffer *ring_buf;
if (!is_power_of_2(size)) {
LOGE("The buffer size is must be power of 2!");
errno = EINVAL;
return NULL;
}
ring_buf = malloc(sizeof(*ring_buf));
if (!ring_buf) {
LOGE("malloc()");
return NULL;
}
ring_buf->data = malloc(size);
if (!ring_buf->data) {
LOGE("malloc()");
free(ring_buf);
return NULL;
}
ring_buf->size = size;
ring_buf->read_pos = 0;
ring_buf->write_pos = 0;
return ring_buf;
}
// 销毁释放 ringBuffer
void ringbuffer_destroy(struct ringbuffer *ring_buf)
{
if (ring_buf) {
if (ring_buf->data) {
free(ring_buf->data);
ring_buf->data = NULL;
}
free(ring_buf);
ring_buf = NULL;
}
}
//从 write_pos 位置向后写,尾部不够再从头部开始写
unsigned int ringbuffer_put(struct ringbuffer *ring_buf,const char *buffer, unsigned int len)
{
unsigned int l;
len = min(len, ring_buf->size - ring_buf->write_pos + ring_buf->read_pos);
/* first put the data starting from write_pos to buffer end */
l = min(len, ring_buf->size - (ring_buf->write_pos & (ring_buf->size - 1)));
memcpy(ring_buf->data + (ring_buf->write_pos & (ring_buf->size - 1)), buffer, l);
/* then put the rest (if any) at the beginning of the buffer */
memcpy(ring_buf->data, buffer + l, len - l);
ring_buf->write_pos += len;
return len;
}
//从 read_pos 位置向后读,尾部不够再从头部开始读
unsigned int ringbuffer_get(struct ringbuffer *ring_buf,char *buffer, unsigned int len)
{
unsigned int l;
len = min(len, ring_buf->write_pos - ring_buf->read_pos);
/* first get the data from ring_buf->read_pos until the end of the buffer */
/* (ring_buf->read_pos & (ring_buf->size - 1)) 的含义是获取 read_pos在 size 中的位置。如果read_pos 大于 size表示已经读取一圈* eg ring_buf->size = 128 ring_buf->size - 1 =127 如果 ring_buf->read_pos=30 小于 127 那么就是0 轮回 30 ,如果 read_pos=150 大于 128 那么就是 1轮回 22 。ring_buf->size - (ring_buf->read_pos & (ring_buf->size - 1)) 算出的就是 从 read_pos 到 end buffer 的 大小*/
l = min(len, ring_buf->size - (ring_buf->read_pos & (ring_buf->size - 1)));
memcpy(buffer, ring_buf->data + (ring_buf->read_pos & (ring_buf->size - 1)), l);
/* then get the rest (if any) from the beginning of the buffer */
memcpy(buffer + l, ring_buf->data, len - l);
ring_buf->read_pos += len;
return len;
}
//清空 ringBuffer
void ringbuffer_reset(struct ringbuffer *ring_buf)
{
ring_buf->write_pos = ring_buf->read_pos = 0;
}
//判断 ringBuffer 是否为空
unsigned int ringbuffer_is_empty(struct ringbuffer *ring_buf)
{
return ring_buf->read_pos == ring_buf->write_pos;
}
//判断 ringBuffer 是否为满
unsigned int ringbuffer_is_full(struct ringbuffer *ring_buf)
{
return ring_buf->size == ring_buf->write_pos - ring_buf->read_pos;
}
//获取 ringBuffer 中有效数据的长度
unsigned int ringbuffer_len(struct ringbuffer *ring_buf)
{
return ring_buf->write_pos - ring_buf->read_pos;
}
//判断 ringBuffer 可用空间
unsigned int ringbuffer_space_left(struct ringbuffer *ring_buf)
{
return ring_buf->size - ring_buf->write_pos + ring_buf->read_pos;
}
1、创建
tmp_fifo_size = 32 * 128; // 2的12次幂 4kb
tmp_fifo = ringbuffer_create(tmp_fifo_size);
2、存放
pthread_mutex_lock (&mutex);
space_left = ringbuffer_space_left(tmp_fifo); //判断剩余空间
if(space_left < tmp_fifo_size/2) {
LOGE("WARNING!!! left space in ringbuffer:%d", space_left);
}
if(space_left >= i2c_data_len) {
ringbuffer_put(tmp_fifo, (const char*)&tmp_buf, i2c_data_len);
}
pthread_mutex_unlock(&mutex);
3、读取
pthread_mutex_lock (&mutex);
ringbuffer_is_empty(tmp_fifo); // 判断是否为空
size = ringbuffer_get(tmp_fifo, (char*)i2c_buf, i2c_data_len); //不为空 获取数据
pthread_mutex_unlock(&mutex);