• C++环形缓冲区


    环形缓冲区(ring buffer)也称作循环缓冲区(cyclic buffer)、圆形队列(circular queue)、圆形缓冲区(circular buffer)。环形缓冲区并不是指物理意义上的一个首尾相连成“环”的缓冲区,而是逻辑意义上的一个环,因为内存空间是线性结构,所以实际上环形缓冲区仍是一段有长度的内存空间,是一个先进先出功能的缓冲区,具备实现通信进程对该缓冲区的互斥访问功能。

    环形缓冲区的长度是固定的,在使用该缓冲区时,不需要将所有的数据清除,只需要调整指向该缓冲区的pHead、pValidWrite和pTail指针位置即可。pValidWrite指针最先指向pHead指针位置(环形缓冲区开头位置),数据从pValidWrite指针处开始存储,每存储一个数据,pValidWrite指针位置向后移动一个长度 ,随着数据的添加,pValidWrite指针随移动数据长度大小个位置。当pValidWrite指向pTail尾部指针,pValidWrite重新指向pHead指针位置(折行处理),并且覆盖原先位置数据内容直到数据存储完毕。

    https://img-blog.csdnimg.cn/20210428110021121.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pob3VtaW5nNQ==,size_16,color_FFFFFF,t_70#pic_center

    一般构建一个环形缓冲区需要一段连续的内存空间以及4个指针:

    pHead指针:指向内存空间中的首地址;

    pTail指针:指向内存空间的尾地址;

    pValidRead:指向内存空间存储数据的起始位置(读指针);

    pValidWrite:指向内存空间存储数据的结尾位置(写指针)。

    当申请完内存以及指针定义完毕后,环形缓冲区说明及使用如下:

    1.该段内存空间的长度是Len = pTail-pHead;

    2.pValidRead是读数据的起始位置,当读取完N数据之后要移动N个单位长度的偏移,当有addlen长度的数据要存入到环形缓冲区,若addlen + pValidWrite > pTail时,pValidWrite将存入len1 = pTail - pValidWrite个数据长度,然后pValidWrite回到pHead位置,将剩下的len2 = addlen - len1个数据从pHead开始存储并覆盖到原来的数据内容。

    3.pValidWrite是写数据的起始位置,当存入N个数据之后要移动N个单位长度的偏移,pValidRead是读数据的起始位置,当读取N个数据之后要移动N个单位长度的偏移。当要addlen长度的数据要从环形缓冲区读取,若addlen + pValidRead > pTail时,pValidRead 将读取len1 = pTail - pValidRead 个数据长度,然后pValidRead 回到pHead位置,将剩下的len2 = addlen - len1个数据从pHead开始读取完毕。

    文件1:ringbuffer.h

    1. Ringbuffer.h
    2. #pragma once
    3. #include<stdio.h>
    4. #include<stdlib.h> //引入malloc动态分配内存
    5. #include<stdint.h> //引入uint32_t,32位无符号整形
    6. #include<string.h> //引入memcpy内存拷贝函数
    7. void InitRingBuffer();
    8. void FreeRingBuffer();
    9. int WriteRingBuffer(uint32_t *pData,int Data_Size);
    10. int ReadRingBuffer(uint32_t* pData, int Data_Size);
    11. int GetRingBufferValidSize();

     文件2:ringbuffer.cpp

    1. Ringbuffer.cpp
    2. #include"RingBuffer.h"
    3. #define BUFFER_SIZE 16 //环形存储区长度
    4. uint32_t* pHead = NULL; //环形缓冲区首地址
    5. uint32_t* pTail = NULL; //环形缓冲区尾地址
    6. uint32_t* pRead = NULL; //读指针
    7. uint32_t* pWrite = NULL; //写指针
    8. int BUFFER_VALID_SIZE; //环形存储区存储的数据大小
    9. //初始化环形缓冲区
    10. void InitRingBuffer()
    11. {
    12. if (pHead == NULL)
    13. {
    14. pHead = (uint32_t*)malloc(BUFFER_SIZE);
    15. }
    16. pRead = pHead;
    17. pWrite = pHead;
    18. pTail = pHead + BUFFER_SIZE;
    19. BUFFER_VALID_SIZE = 0;
    20. }
    21. //释放环形缓冲区
    22. void FreeRingBuffer()
    23. {
    24. if (pHead != NULL) //当存在缓冲区时
    25. {
    26. free(pHead); //释放
    27. }
    28. pHead = NULL; //重新令环形器起始地址为空
    29. BUFFER_VALID_SIZE = 0;
    30. }
    31. //写命令
    32. int WriteRingBuffer(uint32_t* pData, int Data_Size)
    33. {
    34. if (pHead == NULL) //缓冲区未初始化
    35. {
    36. printf("Writing Failed! The ringbuffer is not inited!\n");
    37. return -1;
    38. }
    39. if (Data_Size > BUFFER_SIZE) //加入数据过多
    40. {
    41. printf("Writing Failed! The input data size exceeds the ringbuffer size!\n");
    42. return -2;
    43. }
    44. if (pWrite+Data_Size>pTail)
    45. //将数据存入缓冲区,但是数据需要分成两段
    46. {
    47. int Data_Part1 = pTail - pWrite; //存放在靠近尾部的Data部分
    48. int Data_Part2 = Data_Size - Data_Part1;//存放在靠近头部的Data部分
    49. memcpy(pWrite, pData, Data_Part1 * sizeof(uint32_t));
    50. memcpy(pHead, pData+Data_Part1, Data_Part2 * sizeof(uint32_t));
    51. pWrite = pHead + Data_Part2; //更新写指针
    52. BUFFER_VALID_SIZE = BUFFER_SIZE;
    53. }
    54. else //不用分段
    55. {
    56. memcpy(pWrite, pData, Data_Size * sizeof(uint32_t));
    57. pWrite += Data_Size;//更新写指针
    58. BUFFER_VALID_SIZE += Data_Size;
    59. }
    60. return 0;
    61. }
    62. //读命令
    63. int ReadRingBuffer(uint32_t* pData, int Data_Size)
    64. {
    65. if (pHead == NULL) //缓冲区未初始化
    66. {
    67. printf("Reading Failed! The ringbuffer is not inited!\n");
    68. return -1;
    69. }
    70. if (Data_Size > pTail-pHead) //读出数据过多,超出BUFFER大小
    71. {
    72. printf("Reading Failed! The reading data size exceeds the ringbuffer size!\n");
    73. return -2;
    74. }
    75. //无数据读出
    76. if (Data_Size == 0)
    77. {
    78. printf("Reading Failed! No data exists!\n");
    79. return 0;
    80. }
    81. //判断是否需要分成两段读出
    82. if (pRead + Data_Size > pTail)
    83. {
    84. int Data_Part1 = pTail - pRead;
    85. int Data_Part2 = Data_Size - Data_Part1;
    86. memcpy(pData, pRead, Data_Part1 * sizeof(uint32_t));
    87. memcpy(pData + Data_Part1, pHead, Data_Part2 * sizeof(uint32_t));
    88. pRead = pHead + Data_Part2;
    89. BUFFER_VALID_SIZE -= Data_Size;
    90. }
    91. else
    92. {
    93. memcpy(pData, pRead, Data_Size * sizeof(uint32_t));
    94. pRead += Data_Size;
    95. BUFFER_VALID_SIZE -= Data_Size;
    96. }
    97. return 1;
    98. }
    99. //获取当前缓冲区有效长度,即存储的数据个数
    100. int GetRingBufferValidSize()
    101. {
    102. return BUFFER_VALID_SIZE;
    103. }

     文件3:main.cpp

    1. #include"RingBuffer.h"
    2. #include<iostream>
    3. int main()
    4. {
    5. //InitRingBuffer();
    6. std::cout << "---------------------------------" << std::endl;
    7. std::cout << "Input your choice:" << std::endl;
    8. std::cout << "1. Initializatize the ring buffer." << std::endl;
    9. std::cout << "2. Delete the ring buffer." << std::endl;
    10. std::cout << "3. Write the ring buffer." << std::endl;
    11. std::cout << "4. Read the ring buffer." << std::endl;
    12. std::cout << "---------------------------------" << std::endl;
    13. int choice;
    14. int Len; //存储当前环形缓冲区的数据长度
    15. uint32_t ReadData[5]; //存储读出的数据
    16. uint32_t data[5] = {1,2,3,4,5,}; //假设有5个读入的数据
    17. int Data_Size = 5; //数据大小,占20个字节
    18. while (1)
    19. {
    20. std::cin >> choice;
    21. switch (choice)
    22. {
    23. case 1: InitRingBuffer();
    24. std::cout << "缓冲区初始化成功!" << std::endl;
    25. break;
    26. case 2: FreeRingBuffer();
    27. std::cout << "缓冲区释放成功!" << std::endl;
    28. return 1;
    29. case 3:
    30. std::cout << "执行数据拷贝!" << std::endl;
    31. WriteRingBuffer(data, Data_Size);
    32. break;
    33. case 4:
    34. Len = GetRingBufferValidSize();
    35. std::cout << "当前缓冲区存储的数据个数:" << Len << std::endl;
    36. ReadRingBuffer(ReadData, Data_Size);
    37. if (Len > 0)
    38. {
    39. std::cout << "读取环形存储区的数据为:" << std::endl;
    40. for (int i = 0; i < Len; i++)
    41. {
    42. std::cout << ReadData[i] << std::endl;
    43. }
    44. }
    45. else
    46. {
    47. std::cout << "当前缓冲区无数据!" << std::endl;
    48. }
    49. break;
    50. default:
    51. break;
    52. }
    53. }
    54. system("pause");
    55. return 1;
    56. }

  • 相关阅读:
    JD-H5开发
    linux-xsell、xftp连接虚拟机
    Centos7 安装 Etcd
    微信小程序笔记功能(富文本editor功能)开发
    远勤山丨于无声处听惊雷——写在远航汽车投产下线之际
    【Web安全】注入攻击
    高质量的写作论文竞赛介绍
    手把手开发Admin 系列三(自定义模板篇)
    咖啡价格分析
    网络运维与网络安全 学习笔记2023.11.17
  • 原文地址:https://blog.csdn.net/Lao_tan/article/details/125479022