队列之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
.
/************* 社会的有色眼光是:博士生、研究生、本科生、车间工人; 重点大学高材生、普通院校、二流院校、野鸡大学; 年薪百万、五十万、五万; 这些都只是帽子,可以失败千百次,但我和社会都觉得,人只要成功一次,就能换一顶帽子,只是社会看不见你之前的失败的帽子。 当然,换帽子决不是最终目的,走好自己的路就行。 杭州.大话西游 *******/