队列之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 \n");
215         return -EINVAL;
216     }
217 
218     printf("it->node_available :[ %d ] \n", 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 \n", ++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\n");

      //  in
      data_t_in.data1 = 98;
      data_t_in.data2 = 99;
      if(0 != fifo_enqueue(fifo_it, &data_t_in))
        printf("Error\n");

       // out  
      fifo_dequeue(fifo_it, &data_t_out);
      printf("  fifo_dequeue :    \
          data_t_out.data1 [%d]   data_t_out.data2 [%d]  \n", \
                      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\n");

       // out  
      fifo_dequeue(fifo_it, &data_t_out);
      printf("  fifo_dequeue :    \
          data_t_out.data1 [%d]   data_t_out.data2 [%d]  \n", \
                      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]  \n", \
                      data_t_out.data1, data_t_out.data2);


      printf(" \n\n");
      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

 

 

 

.

posted @ 2020-10-04 17:37  一匹夫  阅读(656)  评论(0编辑  收藏  举报