最近在做网络数据收发操作时,用到环形缓冲区的数据结构,网上看了很多人的实现方式,总觉得不妥,于是决定自己亲自写一个,适用于自己的项目。

先看一张关于环形队列的描述图(如下),它是一种FIFO(先入先出)的队列,其明确队列的容量,存储结构上表现为头尾相连,使用起始位置和结束位置标识队列节点的存储区段。

avatar

更多关于环形队列的描述,这里就不再重复,可至 环形缓冲器(FIFO) 查看。

我给出相关代码的结构定义如下:

  1. /**
  2. * @struct x_ringbuf_t
  3. * @brief 环形缓存的结构体描述信息。
  4. */
  5. typedef struct x_ringbuf_t
  6. {
  7. x_uint32_t xut_vpos; ///< 缓存中有效数据的起始位置
  8. x_uint32_t xut_vlen; ///< 缓存中有效数据的长度
  9. x_uint32_t xut_size; ///< 缓存大小
  10. x_uchar_t * xct_dptr; ///< 缓存地址
  11. } x_ringbuf_t;

从上面的结构体定义中,可以看出,数据区段的结束位置,使用了数据区段的长度来替换了,这样做,可避免 起始位置结束位置 重叠在一起时,表示不清 环形缓存满区段 还是 空区段

  1. /** 判断环形缓存是否有效 */
  2. #define RBUF_IS_VALID(xrbt_sptr) ((X_NULL != (xrbt_sptr)) && \
  3. (X_NULL != (xrbt_sptr)->xct_dptr) && ((xrbt_sptr)->xut_size > 0) && \
  4. ((xrbt_sptr)->xut_vpos >= 0) && ((xrbt_sptr)->xut_vpos < (xrbt_sptr)->xut_size) && \
  5. ((xrbt_sptr)->xut_vlen <= (xrbt_sptr)->xut_size))
  6. /** 判断环形缓存是否为 空 */
  7. #define RBUF_IS_EMPTY(xrbt_sptr) (0 == (xrbt_sptr)->xut_vlen)
  8. /** 判断环形缓存是否为 满 */
  9. #define RBUF_IS_FULL(xrbt_sptr) ((xrbt_sptr)->xut_size == (xrbt_sptr)->xut_vlen)
  10. /**********************************************************/
  11. /**
  12. * @brief 用于 环形缓存的内存申请操作 回调函数类型(内存要释放时,请调用 xfunc_ringbuf_free 指向的接口)。
  13. *
  14. * @param [in ] xht_context : 回调的上下文描述句柄。
  15. * @param [in ] xut_size : 提交申请的内存字节数。
  16. *
  17. * @return x_uchar_t *
  18. * - 操作成功,返回申请到的内存地址;
  19. * - 操作失败,返回 X_NULL。
  20. */
  21. typedef x_uchar_t * (* xfunc_ringbuf_malloc)(x_handle_t xht_context, x_uint32_t xut_size);
  22. /**********************************************************/
  23. /**
  24. * @brief 用于 环形缓存的内存释放操作 回调函数类型(所释放的内存,即为 xfunc_ringbuf_malloc 所申请的)。
  25. *
  26. * @param [in ] xht_context : 回调的上下文描述句柄。
  27. * @param [in ] xpvt_ptr : 要释放的内存地址。
  28. *
  29. */
  30. typedef x_void_t (* xfunc_ringbuf_free)(x_handle_t xht_context, x_void_t * xpvt_ptr);
  31. /**********************************************************/
  32. /**
  33. * @brief 创建 环形缓存对象(使用 rbuf_destroy() 接口进行对象销毁)。
  34. *
  35. * @param [in ] xut_size : 环形缓存 的缓存大小。
  36. * @param [in ] xfunc_mptr : 内存申请操作的回调函数接口(若为 X_NULL,则使用标准 C 的 malloc() 接口进行分配内存)。
  37. * @param [in ] xht_context : 回调的上下文描述句柄。
  38. *
  39. * @return x_ringbuf_t *
  40. * - 操作成功,返回 环形缓存 对象;
  41. * - 操作失败,返回 X_NULL。
  42. */
  43. x_ringbuf_t * rbuf_create(x_uint32_t xut_size, xfunc_ringbuf_malloc xfunc_mptr, x_handle_t xht_context);
  44. /**********************************************************/
  45. /**
  46. * @brief 销毁 环形缓存对象(由 rbuf_create() 接口创建的对象)。
  47. *
  48. * @param [in ] xrbt_sptr : 环形缓存对象。
  49. * @param [in ] xfunc_fptr : 内存释放操作的回调函数接口(若为 X_NULL,则使用标准 C 的 free() 接口进行释放内存)。
  50. * @param [in ] xht_context : 回调的上下文描述句柄。
  51. *
  52. */
  53. x_void_t rbuf_destroy(x_ringbuf_t * xrbt_sptr, xfunc_ringbuf_free xfunc_fptr, x_handle_t xht_context);
  54. /**********************************************************/
  55. /**
  56. * @brief 读取环形缓存对象中的有效数据至指定的缓存中;
  57. * 该操作后,会修改环形缓存中的有效数据相关字段。
  58. *
  59. * @param [in ] xrbt_sptr : 环形缓存对象。
  60. * @param [out] xct_rptr : 指定的数据接收缓存。
  61. * @param [in ] xut_size : 数据接收缓存大小。
  62. *
  63. * @return x_uint32_t
  64. * - 返回读取到的有效数据量(字节数)。
  65. */
  66. x_uint32_t rbuf_read(x_ringbuf_t * xrbt_sptr, x_uchar_t * xct_rptr, x_uint32_t xut_size);
  67. /**********************************************************/
  68. /**
  69. * @brief 向环形缓存对象写入数据;
  70. * 环形缓存剩余的空间量必须足够待写入的数据量,否则直接返回 0,忽略后续操作;
  71. * 该操作后,会修改环形缓存中的有效数据相关字段。
  72. *
  73. * @param [out] xrbt_sptr : 环形缓存对象。
  74. * @param [in ] xct_wptr : 待写入数据的缓存。
  75. * @param [in ] xut_size : 待写入数据的缓存大小。
  76. *
  77. * @return x_uint32_t
  78. * - 返回写入的有效数据量(字节数)。
  79. */
  80. x_uint32_t rbuf_write(x_ringbuf_t * xrbt_sptr, const x_uchar_t * xct_wptr, x_uint32_t xut_size);
  81. /**********************************************************/
  82. /**
  83. * @brief 抹除环形缓存中的头部数据。
  84. *
  85. * @param [out] xrbt_sptr : 环形缓存对象。
  86. * @param [in ] xut_count : 请求抹除的字节数。
  87. *
  88. * @return x_uint32_t
  89. * - 返回抹除的字节数。
  90. */
  91. x_uint32_t rbuf_erase_head(x_ringbuf_t * xrbt_sptr, x_uint32_t xut_count);
  92. /**********************************************************/
  93. /**
  94. * @brief 抹除环形缓存中的尾部数据。
  95. *
  96. * @param [out] xrbt_sptr : 环形缓存对象。
  97. * @param [in ] xut_count : 请求抹除的字节数。
  98. *
  99. * @return x_uint32_t
  100. * - 返回抹除的字节数。
  101. */
  102. x_uint32_t rbuf_erase_tail(x_ringbuf_t * xrbt_sptr, x_uint32_t xut_count);

对于 rbuf_create()rbuf_destroy() 中加入了 内存 申请/释放 的回调操作函数 的参数,这样方便外部介入内存管理操作(使用内存池进行内存的分配与释放操作)。

  1. /**********************************************************/
  2. /**
  3. * @brief 创建 环形缓存对象(使用 rbuf_destroy() 接口进行对象销毁)。
  4. *
  5. * @param [in ] xut_size : 环形缓存 的缓存大小。
  6. * @param [in ] xfunc_mptr : 内存申请操作的回调函数接口(若为 X_NULL,则使用标准 C 的 malloc() 接口进行分配内存)。
  7. * @param [in ] xht_context : 回调的上下文描述句柄。
  8. *
  9. * @return x_ringbuf_t *
  10. * - 操作成功,返回 环形缓存 对象;
  11. * - 操作失败,返回 X_NULL。
  12. */
  13. x_ringbuf_t * rbuf_create(x_uint32_t xut_size, xfunc_ringbuf_malloc xfunc_mptr, x_handle_t xht_context)
  14. {
  15. x_ringbuf_t * xrbt_sptr = X_NULL;
  16. if (xut_size <= 0)
  17. {
  18. return X_NULL;
  19. }
  20. if (X_NULL == xfunc_mptr)
  21. {
  22. xrbt_sptr = (x_ringbuf_t *)malloc(sizeof(x_ringbuf_t) + xut_size);
  23. }
  24. else
  25. {
  26. xrbt_sptr = (x_ringbuf_t *)xfunc_mptr(xht_context, sizeof(x_ringbuf_t) + xut_size);
  27. }
  28. if (X_NULL != xrbt_sptr)
  29. {
  30. xrbt_sptr->xut_vpos = 0;
  31. xrbt_sptr->xut_vlen = 0;
  32. xrbt_sptr->xut_size = xut_size;
  33. xrbt_sptr->xct_dptr = ((x_uchar_t *)xrbt_sptr) + sizeof(x_ringbuf_t);
  34. }
  35. return xrbt_sptr;
  36. }
  37. /**********************************************************/
  38. /**
  39. * @brief 销毁 环形缓存对象(由 rbuf_create() 接口创建的对象)。
  40. *
  41. * @param [in ] xrbt_sptr : 环形缓存对象。
  42. * @param [in ] xfunc_fptr : 内存释放操作的回调函数接口(若为 X_NULL,则使用标准 C 的 free() 接口进行分配内存)。
  43. * @param [in ] xht_context : 回调的上下文描述句柄。
  44. *
  45. */
  46. x_void_t rbuf_destroy(x_ringbuf_t * xrbt_sptr, xfunc_ringbuf_free xfunc_fptr, x_handle_t xht_context)
  47. {
  48. if (X_NULL != xrbt_sptr)
  49. {
  50. if (X_NULL == xfunc_fptr)
  51. {
  52. free(xrbt_sptr);
  53. }
  54. else
  55. {
  56. xfunc_fptr(xht_context, (x_void_t *)xrbt_sptr);
  57. }
  58. }
  59. }
  60. /**********************************************************/
  61. /**
  62. * @brief 读取环形缓存对象中的有效数据至指定的缓存中;
  63. * 该操作后,会修改环形缓存中的有效数据相关字段。
  64. *
  65. * @param [in ] xrbt_sptr : 环形缓存对象。
  66. * @param [out] xct_rptr : 指定的数据接收缓存。
  67. * @param [in ] xut_size : 数据接收缓存大小。
  68. *
  69. * @return x_uint32_t
  70. * - 返回读取到的有效数据量(字节数)。
  71. */
  72. x_uint32_t rbuf_read(x_ringbuf_t * xrbt_sptr, x_uchar_t * xct_rptr, x_uint32_t xut_size)
  73. {
  74. x_uint32_t xut_rbytes = 0;
  75. x_uint32_t xut_cbytes = 0;
  76. XASSERT(RBUF_IS_VALID(xrbt_sptr));
  77. XASSERT((0 == xut_size) || ((xut_size > 0) && (X_NULL != xct_dptr)));
  78. if ((xut_size <= 0) || (xrbt_sptr->xut_vlen <= 0))
  79. {
  80. return 0;
  81. }
  82. xut_rbytes = (xut_size >= xrbt_sptr->xut_vlen) ? xrbt_sptr->xut_vlen : xut_size;
  83. if ((xrbt_sptr->xut_vpos + xut_rbytes) <= xrbt_sptr->xut_size)
  84. {
  85. memcpy(xct_rptr, xrbt_sptr->xct_dptr + xrbt_sptr->xut_vpos, xut_rbytes);
  86. }
  87. else
  88. {
  89. xut_cbytes = xrbt_sptr->xut_size - xrbt_sptr->xut_vpos;
  90. memcpy(xct_rptr, xrbt_sptr->xct_dptr + xrbt_sptr->xut_vpos, xut_cbytes);
  91. memcpy(xct_rptr + xut_cbytes, xrbt_sptr->xct_dptr, xut_rbytes - xut_cbytes);
  92. }
  93. xrbt_sptr->xut_vlen -= xut_rbytes;
  94. if (0 == xrbt_sptr->xut_vlen)
  95. xrbt_sptr->xut_vpos = 0;
  96. else
  97. xrbt_sptr->xut_vpos = (xrbt_sptr->xut_vpos + xut_rbytes) % xrbt_sptr->xut_size;
  98. return xut_rbytes;
  99. }
  100. /**********************************************************/
  101. /**
  102. * @brief 向环形缓存对象写入数据;
  103. * 环形缓存剩余的空间量必须足够待写入的数据量,否则直接返回 0,忽略后续操作;
  104. * 该操作后,会修改环形缓存中的有效数据相关字段。
  105. *
  106. * @param [out] xrbt_sptr : 环形缓存对象。
  107. * @param [in ] xct_wptr : 待写入数据的缓存。
  108. * @param [in ] xut_size : 待写入数据的缓存大小。
  109. *
  110. * @return x_uint32_t
  111. * - 返回写入的有效数据量(字节数)。
  112. */
  113. x_uint32_t rbuf_write(x_ringbuf_t * xrbt_sptr, const x_uchar_t * xct_wptr, x_uint32_t xut_size)
  114. {
  115. x_uint32_t xut_wpos = 0;
  116. x_uint32_t xut_wlen = 0;
  117. XASSERT(RBUF_IS_VALID(xrbt_sptr));
  118. XASSERT((0 == xut_size) || ((xut_size > 0) && (X_NULL != xct_wptr)));
  119. if ((xut_size <= 0) || (xut_size > (xrbt_sptr->xut_size - xrbt_sptr->xut_vlen)))
  120. {
  121. return 0;
  122. }
  123. xut_wpos = (xrbt_sptr->xut_vpos + xrbt_sptr->xut_vlen) % xrbt_sptr->xut_size;
  124. if ((xut_wpos + xut_size) <= xrbt_sptr->xut_size)
  125. {
  126. memcpy(xrbt_sptr->xct_dptr + xut_wpos, xct_wptr, xut_size);
  127. }
  128. else
  129. {
  130. xut_wlen = xrbt_sptr->xut_size - xut_wpos;
  131. memcpy(xrbt_sptr->xct_dptr + xut_wpos, xct_wptr, xut_wlen);
  132. memcpy(xrbt_sptr->xct_dptr, xct_wptr + xut_wlen, xut_size - xut_wlen);
  133. }
  134. xrbt_sptr->xut_vlen += xut_size;
  135. return xut_size;
  136. }
  137. /**********************************************************/
  138. /**
  139. * @brief 抹除环形缓存中的头部数据。
  140. *
  141. * @param [out] xrbt_sptr : 环形缓存对象。
  142. * @param [in ] xut_count : 请求抹除的字节数。
  143. *
  144. * @return x_uint32_t
  145. * - 返回抹除的字节数。
  146. */
  147. x_uint32_t rbuf_erase_head(x_ringbuf_t * xrbt_sptr, x_uint32_t xut_count)
  148. {
  149. x_uint32_t xut_bytes = 0;
  150. XASSERT(RBUF_IS_VALID(xrbt_sptr));
  151. if (xut_count <= 0)
  152. {
  153. return 0;
  154. }
  155. if (xut_count >= xrbt_sptr->xut_vlen)
  156. {
  157. xut_bytes = xrbt_sptr->xut_vlen;
  158. xrbt_sptr->xut_vpos = 0;
  159. xrbt_sptr->xut_vlen = 0;
  160. }
  161. else
  162. {
  163. xut_bytes = xut_count;
  164. xrbt_sptr->xut_vpos = (xrbt_sptr->xut_vpos + xut_count) % xrbt_sptr->xut_size;
  165. xrbt_sptr->xut_vlen -= xut_count;
  166. }
  167. return xut_bytes;
  168. }
  169. /**********************************************************/
  170. /**
  171. * @brief 抹除环形缓存中的尾部数据。
  172. *
  173. * @param [out] xrbt_sptr : 环形缓存对象。
  174. * @param [in ] xut_count : 请求抹除的字节数。
  175. *
  176. * @return x_uint32_t
  177. * - 返回抹除的字节数。
  178. */
  179. x_uint32_t rbuf_erase_tail(x_ringbuf_t * xrbt_sptr, x_uint32_t xut_count)
  180. {
  181. x_uint32_t xut_bytes = 0;
  182. XASSERT(RBUF_IS_VALID(xrbt_sptr));
  183. if (xut_count <= 0)
  184. {
  185. return 0;
  186. }
  187. if (xut_count >= xrbt_sptr->xut_vlen)
  188. {
  189. xut_bytes = xrbt_sptr->xut_vlen;
  190. xrbt_sptr->xut_vpos = 0;
  191. xrbt_sptr->xut_vlen = 0;
  192. }
  193. else
  194. {
  195. xut_bytes = xut_count;
  196. xrbt_sptr->xut_vlen -= xut_count;
  197. }
  198. return xut_bytes;
  199. }

ring_buffer: https://github.com/Gaaagaa/ring_buffer

无锁环形队列的一种高效实现:https://www.cnblogs.com/dodng/p/4367791.html

版权声明:本文为VxGaaagaa原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/VxGaaagaa/p/10012842.html