Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1247398
  • 博文数量: 261
  • 博客积分: 4196
  • 博客等级: 上校
  • 技术积分: 3410
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-17 17:05
文章分类

全部博文(261)

文章存档

2018年(1)

2017年(22)

2016年(2)

2015年(8)

2014年(27)

2013年(40)

2012年(161)

分类: LINUX

2017-11-12 17:35:42

    循环缓冲区在一些竞争问题上提供了一种免锁的机制,免锁的前提是,生产者和消费都只有一个的情况下,否则也要加锁。下面是循环缓存区的代码示例:
fifo.h

  1. #ifndef FIFO_H
  2. #define FIFO_H

  3. typedef unsigned char uchar;
  4. typedef unsigned int uint;


  5. struct _pfifo
  6. {
  7.     uchar *buffer;
  8.     uint size;
  9.     uint in;
  10.     uint out;
  11. };
  12. typedef struct _pfifo Pfifo;

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

  14. void pfifo_reset(Pfifo *p);
  15. uint pfifo_len(Pfifo *p);
  16. uint pfifo_get(Pfifo *fifo, uchar *buffer, uint len);
  17. uint pfifo_put(Pfifo *fifo, uchar *buffer, uint len);
  18. /* size must be 2^n */
  19. Pfifo * pfifo_alloc(uint size);
  20. void pfifo_free(Pfifo *p);

  21. #endif /*FIFO_H*/


fifo.c
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>

  4. #include "fifo.h"

  5. void pfifo_reset(Pfifo *p)
  6. {
  7.     p->in = p->out = 0;
  8. }
  9. uint pfifo_len(Pfifo *p)
  10. {
  11.     return p->in - p->out;
  12. }

  13. uint pfifo_get(Pfifo *fifo, uchar *buffer, uint len)
  14. {
  15.     uint l;

  16.     len = min(len, fifo->in - fifo->out);

  17.      /* first get the data from fifo->out until the end of the buffer */
  18.     l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
  19.     memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);

  20.      /* then get the rest (if any) from the beginning of the buffer */
  21.     memcpy(buffer + l, fifo->buffer, len - l);

  22.     fifo->out += len;
  23.     return len;
  24. }

  25. uint pfifo_put(Pfifo *fifo, uchar *buffer, uint len)
  26. {
  27.     uint l;

  28.     len = min(len, fifo->size - fifo->in + fifo->out);
  29.     /* first put the data starting from fifo->in to buffer end */
  30.     l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
  31.     memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);

  32.     /* then put the rest (if any) at the beginning of the buffer */
  33.     memcpy(fifo->buffer, buffer + l, len - l);

  34.     fifo->in += len;
  35.     return len;
  36. }

  37. Pfifo * pfifo_alloc(uint size)
  38. {
  39.     Pfifo *fifo = NULL;
  40.     uchar *buffer;

  41.     buffer = malloc(size);
  42.     if (!buffer ) {
  43.         printf("failed to malloc buffer!\n");
  44.         goto err1;
  45.     }

  46.     fifo = malloc(sizeof(Pfifo));
  47.     if (!fifo) {
  48.         printf("failed to malloc Pfifo!\n");
  49.         goto err2;
  50.     }
  51.     fifo->buffer = buffer;
  52.     fifo->size = size;
  53.     fifo->in = fifo->out = 0;

  54.     return fifo;

  55. err2:
  56.     free(buffer);
  57. err1:
  58.     return NULL;
  59. }

  60. void pfifo_free(Pfifo *p)
  61. {
  62.     free(p->buffer);
  63.     p->buffer = NULL;
  64.     free(p);
  65.     p = NULL;
  66. }

  67. Pfifo * fifo;

  68. void test(void)
  69. {
  70.     uchar buf[256] ;
  71.     uint last, this;
  72.     int ret, i;
  73.     
  74.     while (1) {
  75.         ret = pfifo_get(fifo, buf,256);
  76.         if (ret == 0 ) {
  77.             usleep(1000);
  78.             continue;
  79.         }
  80.         
  81.         for (i = 0 ; i < ret ; i++ ) {
  82.            this = buf[i];
  83.            if (this != ((last + 1)%127)) {
  84.                printf("this %d last %d\n");
  85.            }
  86.            last = this;
  87.         }
  88.         last = this;
  89.     }
  90. }

  91. int main(int argc, char *argv[])
  92. {
  93.     uchar buf[127];
  94.     int i, ret;
  95.     pthread_t id;

  96.     for (i = 0 ; i <127 ; i++ )
  97.         buf[i] = i;

  98.     fifo = pfifo_alloc(1024);

  99.     ret = pthread_create(&id,NULL,test,NULL);
  100.     if (ret < 0) {
  101.         printf("pthread create failed !\n");
  102.     }

  103.     while (1 ) {
  104.         ret = pfifo_put(fifo,buf,127);
  105.         if (ret < 127 ) {
  106.             usleep(5000);
  107.             pfifo_put(fifo,buf + ret,127 - ret);
  108.         }
  109.     }

  110.     pfifo_free(fifo);
  111.     return 0;
  112. }
    这两个读写结构才是循环缓冲区的重点。在fifo结构中,size是缓冲区的大小,是由用户自己定义的,但是在这个设计当中要求它的大小必须是2的幂次。当in==out时,表明缓冲区为空的,当(in-out)==size 时,说明缓冲区已满。
    
我们看fifo->in &(fifo->size-1) 这个表达式是什么意思呢?我们知道size是2的幂次项,那么它减1即表示其值的二进制所有位都为1,与in相与的最终结果是in%size,比size要小,所以看in及out的值都是不断地增加,但再相与操作后,它们即是以size为周期的一个循环。 l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));就是比较要写入的数据应该是多少,如果缓冲区后面的还有足够的空间可写,那么把全部的值写到后面,否则写满后面,再写到前面去memcpy(fifo->buffer, buffer + l, len - l);读数据也可以作类似的分析,len = min(len, fifo->in - fifo->out);表示请求的数据要比缓冲区的数据要大时,只读取缓冲区中可用的数据。
阅读(5322) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~