linux ringbuffer原理,linux内核 使用内核队列实现ringbuffer(续)

一、ring buffer

在以前的一篇文章--网络编程中接受缓冲的ringbuf的简单实现介绍了一个自己写的ringbuffer,其实原理和linux内核中的队列很相似,思想是一样的,只不过处理的没有内核那么恰当巧妙,这里也可以使用linux内核中的队列实现之。

/**@brief 仿照linux kfifo写的ring buffer

*@atuher Anker date:2013-12-18

* ring_buffer.h

* */

#ifndef KFIFO_HEADER_H

#define KFIFO_HEADER_H

#include

#include

#include

#include

#include

#include

//判断x是否是2的次方

#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))

//取a和b中最小值

#define min(a, b) (((a) < (b)) ? (a) : (b))

struct ring_buffer

{

void *buffer; //缓冲区

uint32_t size; //大小

uint32_t in; //入口位置

uint32_t out; //出口位置

pthread_mutex_t *f_lock; //互斥锁

};

//初始化缓冲区

struct ring_buffer* ring_buffer_init(void *buffer, uint32_t size, pthread_mutex_t *f_lock)

{

assert(buffer);

struct ring_buffer *ring_buf = NULL;

if (!is_power_of_2(size))

{

fprintf(stderr,"size must be power of 2.

");

return ring_buf;

}

ring_buf = (struct ring_buffer *)malloc(sizeof(struct ring_buffer));

if (!ring_buf)

{

fprintf(stderr,"Failed to malloc memory,errno:%u,reason:%s",

errno, strerror(errno));

return ring_buf;

}

memset(ring_buf, 0, sizeof(struct ring_buffer));

ring_buf->buffer = buffer;

ring_buf->size = size;

ring_buf->in = 0;

ring_buf->out = 0;

ring_buf->f_lock = f_lock;

return ring_buf;

}

//释放缓冲区

void ring_buffer_free(struct ring_buffer *ring_buf)

{

if (ring_buf)

{

if (ring_buf->buffer)

{

free(ring_buf->buffer);

ring_buf->buffer = NULL;

}

free(ring_buf);

ring_buf = NULL;

}

}

//缓冲区的长度

uint32_t __ring_buffer_len(const struct ring_buffer *ring_buf)

{

return (ring_buf->in - ring_buf->out);

}

//从缓冲区中取数据

uint32_t __ring_buffer_get(struct ring_buffer *ring_buf, void * buffer, uint32_t size)

{

assert(ring_buf || buffer);

uint32_t len = 0;

size = min(size, ring_buf->in - ring_buf->out);

/* first get the data from fifo->out until the end of the buffer */

len = min(size, ring_buf->size - (ring_buf->out & (ring_buf->size - 1)));

memcpy(buffer, ring_buf->buffer + (ring_buf->out & (ring_buf->size - 1)), len);

/* then get the rest (if any) from the beginning of the buffer */

memcpy(buffer + len, ring_buf->buffer, size - len);

ring_buf->out += size;

return size;

}

//向缓冲区中存放数据

uint32_t __ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)

{

assert(ring_buf || buffer);

uint32_t len = 0;

size = min(size, ring_buf->size - ring_buf->in + ring_buf->out);

/* first put the data starting from fifo->in to buffer end */

len = min(size, ring_buf->size - (ring_buf->in & (ring_buf->size - 1)));

memcpy(ring_buf->buffer + (ring_buf->in & (ring_buf->size - 1)), buffer, len);

/* then put the rest (if any) at the beginning of the buffer */

memcpy(ring_buf->buffer, buffer + len, size - len);

ring_buf->in += size;

return size;

}

uint32_t ring_buffer_len(const struct ring_buffer *ring_buf)

{

uint32_t len = 0;

pthread_mutex_lock(ring_buf->f_lock);

len = __ring_buffer_len(ring_buf);

pthread_mutex_unlock(ring_buf->f_lock);

return len;

}

uint32_t ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, uint32_t size)

{

uint32_t ret;

pthread_mutex_lock(ring_buf->f_lock);

ret = __ring_buffer_get(ring_buf, buffer, size);

//buffer中没有数据

if (ring_buf->in == ring_buf->out)

ring_buf->in = ring_buf->out = 0;

pthread_mutex_unlock(ring_buf->f_lock);

return ret;

}

uint32_t ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)

{

uint32_t ret;

pthread_mutex_lock(ring_buf->f_lock);

ret = __ring_buffer_put(ring_buf, buffer, size);

pthread_mutex_unlock(ring_buf->f_lock);

return ret;

}

#endif

采用多线程模拟生产者和消费者编写测试程序,如下所示:

/**@brief ring buffer测试程序,创建两个线程,一个生产者,一个消费者。

* 生产者每隔1秒向buffer中投入数据,消费者每隔2秒去取数据。

*@atuher Anker date:2013-12-18

* */

#include "ring_buffer.h"

#include

#include

#define BUFFER_SIZE 1024 * 1024

typedef struct student_info

{

uint64_t stu_id;

uint32_t age;

uint32_t score;

}student_info;

void print_student_info(const student_info *stu_info)

{

assert(stu_info);

printf("id:%lu",stu_info->stu_id);

printf("age:%u",stu_info->age);

printf("score:%u

",stu_info->score);

}

student_info * get_student_info(time_t timer)

{

student_info *stu_info = (student_info *)malloc(sizeof(student_info));

if (!stu_info)

{

fprintf(stderr, "Failed to malloc memory.

");

return NULL;

}

srand(timer);

stu_info->stu_id = 10000 + rand() % 9999;

stu_info->age = rand() % 30;

stu_info->score = rand() % 101;

print_student_info(stu_info);

return stu_info;

}

void * consumer_proc(void *arg)

{

struct ring_buffer *ring_buf = (struct ring_buffer *)arg;

student_info stu_info;

while(1)

{

sleep(2);

printf("------------------------------------------

");

printf("get a student info from ring buffer.

");

ring_buffer_get(ring_buf, (void *)&stu_info, sizeof(student_info));

printf("ring buffer length: %u

", ring_buffer_len(ring_buf));

print_student_info(&stu_info);

printf("------------------------------------------

");

}

return (void *)ring_buf;

}

void * producer_proc(void *arg)

{

time_t cur_time;

struct ring_buffer *ring_buf = (struct ring_buffer *)arg;

while(1)

{

time(&cur_time);

srand(cur_time);

int seed = rand() % 11111;

printf("******************************************

");

student_info *stu_info = get_student_info(cur_time + seed);

printf("put a student info to ring buffer.

");

ring_buffer_put(ring_buf, (void *)stu_info, sizeof(student_info));

printf("ring buffer length: %u

", ring_buffer_len(ring_buf));

printf("******************************************

");

sleep(1);

}

return (void *)ring_buf;

}

int consumer_thread(void *arg)

{

int err;

pthread_t tid;

err = pthread_create(&tid, NULL, consumer_proc, arg);

if (err != 0)

{

fprintf(stderr, "Failed to create consumer thread.errno:%u, reason:%s

",

errno, strerror(errno));

return -1;

}

return tid;

}

int producer_thread(void *arg)

{

int err;

pthread_t tid;

err = pthread_create(&tid, NULL, producer_proc, arg);

if (err != 0)

{

fprintf(stderr, "Failed to create consumer thread.errno:%u, reason:%s

",

errno, strerror(errno));

return -1;

}

return tid;

}

int main()

{

void * buffer = NULL;

uint32_t size = 0;

struct ring_buffer *ring_buf = NULL;

pthread_t consume_pid, produce_pid;

pthread_mutex_t *f_lock = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));

if (pthread_mutex_init(f_lock, NULL) != 0)

{

fprintf(stderr, "Failed init mutex,errno:%u,reason:%s

",

errno, strerror(errno));

return -1;

}

buffer = (void *)malloc(BUFFER_SIZE);

if (!buffer)

{

fprintf(stderr, "Failed to malloc memory.

");

return -1;

}

size = BUFFER_SIZE;

ring_buf = ring_buffer_init(buffer, size, f_lock);

if (!ring_buf)

{

fprintf(stderr, "Failed to init ring buffer.

");

return -1;

}

#if 0

student_info *stu_info = get_student_info(638946124);

ring_buffer_put(ring_buf, (void *)stu_info, sizeof(student_info));

stu_info = get_student_info(976686464);

ring_buffer_put(ring_buf, (void *)stu_info, sizeof(student_info));

ring_buffer_get(ring_buf, (void *)stu_info, sizeof(student_info));

print_student_info(stu_info);

#endif

printf("multi thread test.......

");

produce_pid = producer_thread((void*)ring_buf);

consume_pid = consumer_thread((void*)ring_buf);

pthread_join(produce_pid, NULL);

pthread_join(consume_pid, NULL);

ring_buffer_free(ring_buf);

free(f_lock);

return 0;

}

测试结果如下:

965427525e16842415444a46a8844066.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值