• 队列之ring_buffer优雅实现--附个人代码理解


    1. 下面张贴实现该队列仅需的两个头文件:ring_buffer_iterator.h 和 fifo_iterator.h

    ring_buffer_iterator.h

      1 /*
      2  *
      3  *  This program is free software; you can redistribute it and/or modify it
      4  *  under  the terms of the GNU General  Public License as published by the
      5  *  Free Software Foundation;  either version 2 of the License, or (at your
      6  *  option) any later version.
      7  *
      8  *  You should have received a copy of the GNU General Public License along
      9  *  with this program; if not, write to the Free Software Foundation, Inc.,
     10  *  675 Mass Ave, Cambridge, MA 02139, USA.
     11  *
     12  */
     13 
     14 
     15 #ifndef _RING_BUFFER_ITERATOR_H_
     16 #define _RING_BUFFER_ITERATOR_H_
     17 
     18 #include <unistd.h>
     19 #include <signal.h>
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <errno.h>
     24 #include <stdint.h>
     25 
     26 struct ring_buffer_iterator {
     27     int head;          // 标识下一个待出队元素被存放的位置
     28     int tail;          // 标识下一个新入队元素将被存放的位置
     29 
     30     void *buffer;      // 外部已经申请好的一片内存 
     31     int node_size;     // 每个节点信息所占用的内存大小
     32     int node_capacity; // 标识允许挂接的节点数量
     33     int node_available;// 标识已经挂接的节点数量
     34 };
     35 
     36 // 创建一个队列容器:队列所需的内存在外部分配,此处所谓的队列容器仅仅是维护一个记录相关信息的数据结构表。
     37 static inline struct ring_buffer_iterator *alloc_ring_buffer_iterator(
     38         void *buffer, int node_size, int node_capacity)
     39 {
     40     struct ring_buffer_iterator *iterator;
     41 
     42     if (!buffer) {
     43         return NULL;
     44     }
     45 
     46     if (node_size <= 0) {
     47         return NULL;
     48     }
     49 
     50     iterator = malloc( sizeof(struct ring_buffer_iterator) );
     51     if (!iterator) {
     52         return NULL;
     53     }
     54 
     55     memset(iterator, 0x00, sizeof(struct ring_buffer_iterator) );
     56 
     57     //从这里可以看出,队列所需的内存在外部分配。此处所谓的队列容器仅仅是维护一个记录相关信息的数据结构表。
     58     iterator->buffer = buffer;
     59     iterator->node_size = node_size;
     60     iterator->node_capacity = node_capacity;
     61 
     62     return iterator;
     63 }
     64 
     65 static inline void free_ring_buffer_iterator(struct ring_buffer_iterator *it)
     66 {
     67     if (!it) {
     68         return ;
     69     }
     70 
     71     free(it);
     72 }
     73 static inline int ring_buffer_get(struct ring_buffer_iterator *it, void *buffer)
     74 {
     75     void *node;
     76 
     77     if (!it || !buffer) {
     78         return -EINVAL;
     79     }
     80 
     81     if (!it->node_available) {
     82         return -ENODATA;
     83     }
     84        // 求出待读取的队列元素数据的首地址。
     85     node = (uint8_t *)it->buffer + it->head * it->node_size;
     86 
     87     // 临界点处理 : 当head的值为node_capacity-1时,下一个待读取的元素就是位置下标0处了。
     88     if (it->head == it->node_capacity - 1) {
     89         /*
     90          * case of rolling at the end of buffer
     91          */
     92         it->head = 0;
     93 
     94     } else { // 非临界点处理,head自增即可 
     95         it->head++;
     96     }
     97 
     98     it->node_available--;
     99 
    100     memmove(buffer, node, it->node_size);
    101 
    102     return 0;
    103 }
    104 
    105 
    106 static inline int ring_buffer_peek(struct ring_buffer_iterator *it, void *buffer)
    107 {
    108     void *node;
    109 
    110     if (!it || !buffer) {
    111         return -EINVAL;
    112     }
    113 
    114     if (!it->node_capacity) {
    115         return -ENODATA;
    116     }
    117 
    118     node = (uint8_t *)it->buffer + it->head * it->node_size;
    119 
    120     memmove(buffer, node, it->node_size);
    121 
    122     return 0;
    123 }
    124 
    125 
    126 static inline int ring_buffer_put(struct ring_buffer_iterator *it, void *buffer)
    127 {
    128     void *node;
    129 
    130     if (!it || !buffer) {
    131         return -EINVAL;
    132     }
    133 
    134     /*  对下方的问题1的解答:
    135     队列中有数据的情况下,head和tail还会有相等的场景么。
    136     我认为不会进入这种情况,这段代码是多余的。
    137     */
    138     if (it->node_available) {
    139 
    140          // 新元素入队待存放地址下标 什么时候 等于 待出队元素的地址下标呢?《== 问题1
    141         if (it->tail == it->head) {
    142             /*
    143              * case of rolling to buffer over lapped
    144              */
    145             if (it->node_capacity != 1) {
    146                 /*
    147                  * case of not single node capacity buffer
    148                  */
    149                 if (it->tail == it->node_available - 1) {
    150                     /*
    151                      * case of rolling to end of buffer
    152                      */
    153                     it->head = 0;
    154                 } else {
    155                     it->head = it->tail + 1;
    156                 }
    157             }
    158 
    159         }
    160     } /* end of it->node_available */
    161 
    162     node = (uint8_t *)it->buffer + it->tail *it->node_size;
    163     memmove(node, buffer, it->node_size);
    164 
    165     if (it->tail == it->node_capacity - 1) {
    166         /* 更新下一个入队元素将要被存放的地址下标。
    167          * rolling to end of buffer
    168          */
    169         it->tail = 0;
    170     } else {
    171         it->tail++;
    172     }
    173 
    174     if (it->node_available != it->node_capacity) {
    175         it->node_available++;
    176     }
    177 
    178     return 0;
    179 }
    180 
    181 static inline void ring_buffer_clear(struct ring_buffer_iterator *it)
    182 {
    183     if (!it) {
    184         return;
    185     }
    186 
    187     it->head = 0;
    188     it->tail = 0;
    189     it->node_available = 0;
    190     it->node_capacity  = 0;
    191 }
    192 
    193 
    194 /*
    195  * =1: the ring buffer is full
    196  * =0: the ring buffer is not full
    197  */
    198 static inline int ring_buffer_full(struct ring_buffer_iterator *it)
    199 {
    200     if (!it) {
    201         return -EINVAL;
    202     }
    203 
    204     return it->node_available == it->node_capacity;
    205 }
    206 
    207 /*
    208  * =1: the ring buffer is empty
    209  * =0: the ring buffer is not empty
    210  */
    211 static inline int ring_buffer_empty(struct ring_buffer_iterator *it)
    212 {
    213     if (!it) {
    214         printf("it = NULL 
    ");
    215         return -EINVAL;
    216     }
    217 
    218     printf("it->node_available :[ %d ] 
    ", it->node_available);
    219 
    220     return !(it->node_available);
    221 }
    222 
    223 static inline int ring_buffer_capacity(struct ring_buffer_iterator *it)
    224 {
    225     if (!it) {
    226         return -EINVAL;
    227     }
    228 
    229     return (it->node_capacity);
    230 }
    231 
    232 static inline int ring_buffer_available(struct ring_buffer_iterator *it)
    233 {
    234     if (!it) {
    235         return -EINVAL;
    236     }
    237 
    238     return (it->node_available);
    239 }
    240 
    241 
    242 
    243 #endif /* _RING_BUFFER_ITERATOR_H_ */

    fifo_iterator.h

    /*
     *
     *  This program is free software; you can redistribute it and/or modify it
     *  under  the terms of the GNU General  Public License as published by the
     *  Free Software Foundation;  either version 2 of the License, or (at your
     *  option) any later version.
     *
     *  You should have received a copy of the GNU General Public License along
     *  with this program; if not, write to the Free Software Foundation, Inc.,
     *  675 Mass Ave, Cambridge, MA 02139, USA.
     *
     */
    
    
    #ifndef _FIFO_ITERATOR_H_
    #define _FIFO_ITERATOR_H_
    
    #include "ring_buffer_iterator.h"
    
    struct fifo_iterator {
        struct ring_buffer_iterator *ring_it;
    };
    
    // 创建一个迭代器,创建一个容器实,并让该迭代器指向该容器。
    static inline struct fifo_iterator *alloc_fifo_iterator(
            void *buffer, int size, int capacity)
    {
        // 创建一个迭代器
        struct fifo_iterator *iterator = malloc(sizeof(struct fifo_iterator));
    
        if (!iterator) {
            return NULL;
        }
    
        // 创建一个容器,并让该迭代器指向该容器。   
        iterator->ring_it = alloc_ring_buffer_iterator(buffer, size, capacity);
        if (!iterator->ring_it) {
            return NULL;
        }
    
        return iterator;
    }
    
    static inline void free_fifo_iterator(struct fifo_iterator *it)
    {
        if (it && it->ring_it) {
            free_ring_buffer_iterator(it->ring_it);
        }
    
        if (it) {
            free(it);
        }
    }
    
    /*
     * =1: fifo buffer is full
     * =0: fifo buffer is not full
     */
    static inline int fifo_full(struct fifo_iterator *it)
    {
        return ring_buffer_full(it->ring_it);
    }
    
    /*
     * =1: fifo buffer is empty
     * =0: fifo buffer is not empty
     */
    static inline int fifo_empty(struct fifo_iterator *it)
    {
        return ring_buffer_empty(it->ring_it);
    }
    
    static inline int fifo_enqueue(struct fifo_iterator *it, void *buffer)
    {
        if (ring_buffer_full(it->ring_it)) {
            return -EOVERFLOW;
        }
    
        static int i=0;
        printf("enQuence Success! %d 
    ", ++i);
        return ring_buffer_put(it->ring_it, buffer);
    }
    
    static inline int fifo_dequeue(struct fifo_iterator *it, void *buffer)
    {
        return ring_buffer_get(it->ring_it, buffer);
    }
    
    static inline int fifo_peek(struct fifo_iterator *it, void *buffer)
    {
        return ring_buffer_peek(it->ring_it, buffer);
    }
    
    #endif /* _FIFO_ITERATOR_H_ */

    2. 测试代码展示

    main.c

    #include <stdio.h>
    #include "fifo_iterator.h"
    
    typedef struct _mydatastruct{
    
        int data1;
        int data2;
    
    }mydatastruct;
    
    mydatastruct data_t_in, data_t_out;
    
    #define  fifo_array   4
    
    int main()
    {
        struct fifo_iterator * fifo_it = NULL;
        
        void* pbuff = malloc(sizeof(mydatastruct)*fifo_array);
    
        /*  alloc_fifo_iterator(void *buffer, int size, int capacity)函数内部 : 
                fifo_it->ring_it->buffer = buffer;
                fifo_it->ring_it->node_size = node_size;
                fifo_it->ring_it->node_capacity = node_capacity;  
        */
        fifo_it = alloc_fifo_iterator(pbuff, sizeof(mydatastruct), fifo_array);
    
        while(1)
        {
    
          //  in
          data_t_in.data1 = 88; 
          data_t_in.data2 = 89;
          if(0 != fifo_enqueue(fifo_it, &data_t_in))
            printf("Error
    ");
    
          //  in
          data_t_in.data1 = 98;
          data_t_in.data2 = 99;
          if(0 != fifo_enqueue(fifo_it, &data_t_in))
            printf("Error
    ");
    
           // out  
          fifo_dequeue(fifo_it, &data_t_out);
          printf("  fifo_dequeue :    
              data_t_out.data1 [%d]   data_t_out.data2 [%d]  
    ", 
                          data_t_out.data1, data_t_out.data2);
          //  in
          data_t_in.data1 = 100;
          if(0 != fifo_enqueue(fifo_it, &data_t_in))
            printf("Error
    ");
    
           // out  
          fifo_dequeue(fifo_it, &data_t_out);
          printf("  fifo_dequeue :    
              data_t_out.data1 [%d]   data_t_out.data2 [%d]  
    ", 
                          data_t_out.data1, data_t_out.data2);
    
           // out  
          fifo_dequeue(fifo_it, &data_t_out);
          printf("  fifo_dequeue :    
              data_t_out.data1 [%d]  data_t_out.data2 [%d]  
    ", 
                          data_t_out.data1, data_t_out.data2);
    
    
          printf(" 
    
    ");
          sleep(1);
        }
    
        return 0;
    }

    makefile:

    .PHONY: doit
    
    doit:
        #mips-linux-gnu-gcc -g main.c -o  main_app
        gcc -g main.c -o  main_app

    .

    /************* 社会的有色眼光是:博士生、研究生、本科生、车间工人; 重点大学高材生、普通院校、二流院校、野鸡大学; 年薪百万、五十万、五万; 这些都只是帽子,可以失败千百次,但我和社会都觉得,人只要成功一次,就能换一顶帽子,只是社会看不见你之前的失败的帽子。 当然,换帽子决不是最终目的,走好自己的路就行。 杭州.大话西游 *******/
  • 相关阅读:
    aircrack-ng 多网卡启动后环境清理
    Docker create image
    预加载(学习一)
    activity+fragment多次切换出现页面空白问题
    万能的Volley
    关于下拉刷新你是否真的非常理解还是只会搬砖?附 Android 实例子源代码文件下载地址380个合集
    如何将Java源代码文件的编码从GBK转为UTF-8?
    如何操作笔记本显得逼格很高?
    跑马灯源代码
    关于java、Android中Math的一些用法
  • 原文地址:https://www.cnblogs.com/happybirthdaytoyou/p/13767835.html
Copyright © 2020-2023  润新知