循环队列——实现ringbuffer为了多媒体数据缓存

http://blog.csdn.net/firehood_/article/details/6716357


        在WINCE开发中很多时候需要用到循环队列来缓存数据,比如在串口通信中,可以将接收到的数据流先缓存到循环队列中,然后再从循环队列中取出数据做下一步的处理。这样可以有效的避免解析数据帧时繁琐的拼接处理。

        为了方便使用,封装了一个循环队列类,具体代码如下:

        头文件:

[cpp]  view plain  copy
  1. /******************************************************************** 
  2. filename:   CircularQueue.h 
  3. created:    2011-08-23 
  4. author:     firehood 
  5.  
  6. purpose:    实现循环队列 
  7.             队列可以缓存的数据大小 = 队列长度 -1 
  8.             插入数据时在队列满的情况下会自动覆盖队列头部数据 
  9. *********************************************************************/  
  10. #pragma once  
  11.   
  12. #define DEFAULT_QUEUE_MAX_SIZE  512  
  13. class CCircularQueue  
  14. {  
  15. public:  
  16.     // 无参构造函数,默认创建队列的大小为512字节  
  17.     CCircularQueue(void);  
  18.     // 带参构造函数,创建指定大小的队列  
  19.     CCircularQueue(int nQueueSize);  
  20.     ~CCircularQueue(void);  
  21. public:  
  22.     // 向队列尾部插入一个字节,队列满时会自动覆盖队列头部数据  
  23.     bool PushBack(unsigned char data);  
  24.   
  25.     // 从队列头部取出一个字节  
  26.     bool PopFront(unsigned char &data);  
  27.   
  28.     // 向队列尾部插入指定长度数据,队列满时会自动覆盖队列头部数据  
  29.     bool PushBack(unsigned char *pData, int size);  
  30.       
  31.     // 从队列头部取出指定长度数据  
  32.     // 返回值:>0 返回实际取出的数据长度; <=0 失败  
  33.     int PopFront(unsigned char *pData, int size);  
  34.       
  35.     // 重新调整队列大小  
  36.     bool Resize(int nQueueSize);  
  37.       
  38.     // 当前队列缓存的数据大小  
  39.     int Size();  
  40.     // 队列当前剩余空间大小  
  41.     int RemainSize();  
  42.     // 队列是否为空  
  43.     bool IsEmpty();  
  44.     // 队列是否满  
  45.     bool IsFull();  
  46.     // 打印数据(测试使用)  
  47.     void PrintData();  
  48. private:  
  49.     unsigned char *m_pQueueBase; // 队列基址  
  50.     int m_QueueSize;             // 队列大小  
  51.     int m_Head, m_Tail;          // 队列头尾指针  
  52.     CRITICAL_SECTION  m_csRW;    // 读写锁  
  53. };  

        源文件:

[cpp]  view plain  copy
  1. /******************************************************************** 
  2. filename:   CircularQueue.cpp 
  3. created:    2011-08-23 
  4. author:     firehood 
  5.  
  6. purpose:    实现循环队列 
  7.             队列可以缓存的数据大小 = 队列长度 -1 
  8.             插入数据时在队列满的情况下会自动覆盖队列头部数据 
  9. *********************************************************************/  
  10. #include "stdafx.h"  
  11. #include "CircularQueue.h"  
  12.   
  13. CCircularQueue::CCircularQueue(void):  
  14. m_pQueueBase(NULL),  
  15. m_Head(0),  
  16. m_Tail(0),  
  17. m_QueueSize(DEFAULT_QUEUE_MAX_SIZE)  
  18. {  
  19.     m_pQueueBase = new unsigned char[m_QueueSize];  
  20.     ASSERT(m_pQueueBase);  
  21.     memset(m_pQueueBase, 0, m_QueueSize);  
  22.     InitializeCriticalSection(&m_csRW);  
  23. }  
  24.   
  25. CCircularQueue::CCircularQueue(int nQueueSize):  
  26. m_pQueueBase(NULL),  
  27. m_Head(0),  
  28. m_Tail(0),  
  29. m_QueueSize(nQueueSize)  
  30. {  
  31.     m_pQueueBase = new unsigned char[m_QueueSize];  
  32.     ASSERT(m_pQueueBase);  
  33.     memset(m_pQueueBase, 0, m_QueueSize);  
  34.     InitializeCriticalSection(&m_csRW);  
  35. }  
  36.   
  37. CCircularQueue::~CCircularQueue(void)  
  38. {  
  39.     if(m_pQueueBase)  
  40.     {  
  41.         delete[] m_pQueueBase;  
  42.         m_pQueueBase = NULL;  
  43.     }  
  44.     DeleteCriticalSection (&m_csRW);  
  45. }  
  46.   
  47. // 向队列尾部插入一个字节,队列满时会自动覆盖队列头部数据  
  48. bool CCircularQueue::PushBack(unsigned char data)  
  49. {  
  50.     if(m_pQueueBase == NULL)  
  51.     {  
  52.         return false;  
  53.     }  
  54.     EnterCriticalSection(&m_csRW);  
  55.   
  56.     m_pQueueBase[m_Tail]= data;  
  57.     m_Tail =(m_Tail+1) % m_QueueSize;  
  58.     if(m_Tail == m_Head)  
  59.     {  
  60.         m_Head = m_Tail+1;  
  61.         printf("Warning:lost data, Queue is full..\n");  
  62.     }  
  63.   
  64.     LeaveCriticalSection(&m_csRW);  
  65.     return true;  
  66. }  
  67.   
  68. // 从队列头部取出一个字节  
  69. bool CCircularQueue::PopFront(unsigned char &data)  
  70. {  
  71.     if(m_pQueueBase == NULL)  
  72.     {  
  73.         return false;  
  74.     }  
  75.     if(IsEmpty())  
  76.     {  
  77.         return false;  
  78.     }  
  79.     EnterCriticalSection(&m_csRW);  
  80.   
  81.     data = m_pQueueBase[m_Head];  
  82.     m_Head=(m_Head+1) % m_QueueSize;  
  83.   
  84.     LeaveCriticalSection(&m_csRW);  
  85.     return true;  
  86. }  
  87.   
  88. // 向队列尾部插入指定长度数据,队列满时会自动覆盖队列头部数据  
  89. bool CCircularQueue::PushBack(unsigned char *pData, int size)  
  90. {  
  91.     if(m_pQueueBase == NULL || pData == NULL)  
  92.     {  
  93.         return false;  
  94.     }  
  95.     if(size >= m_QueueSize)  
  96.     {  
  97.         printf("PushBack failed: DataSize[%d] > MAX_QUEUE_SIZE[%d]\n" , size, (m_QueueSize-1));  
  98.         return false;  
  99.     }  
  100.     EnterCriticalSection(&m_csRW);  
  101.     int nRemianSize = RemainSize();  
  102.     int nTailToEndSize = m_QueueSize - m_Tail;  
  103.     if(size <= nTailToEndSize)  
  104.     {  
  105.         memcpy(m_pQueueBase+m_Tail, pData, size);  
  106.     }  
  107.     else  
  108.     {  
  109.         memcpy(m_pQueueBase+m_Tail, pData, nTailToEndSize);  
  110.         memcpy(m_pQueueBase,pData+nTailToEndSize, size-nTailToEndSize);  
  111.     }  
  112.     m_Tail = (m_Tail+size) % m_QueueSize;  
  113.     if(size >= nRemianSize)  
  114.     {  
  115.         printf("Warning:lost data, Queue is full..\n");  
  116.         m_Head = m_Tail+1;  
  117.     }  
  118.     LeaveCriticalSection(&m_csRW);  
  119.     return true;  
  120. }  
  121.   
  122. // 从队列头部取出指定长度数据  
  123. // 返回值:>0 返回实际取出的数据长度; <=0 失败  
  124. int CCircularQueue::PopFront(unsigned char *pData, int size)  
  125. {  
  126.     if(pData == NULL || m_pQueueBase == NULL)  
  127.         return -1;  
  128.       
  129.     EnterCriticalSection(&m_csRW);  
  130.     int nReadSize = (this->Size()>size) ? size : this->Size();  
  131.     int nHeadToEndSize = m_QueueSize - m_Head;  
  132.     if(nReadSize <= nHeadToEndSize)  
  133.     {  
  134.         memcpy(pData, m_pQueueBase+m_Head, nReadSize);  
  135.     }  
  136.     else  
  137.     {  
  138.         memcpy(pData,m_pQueueBase+m_Head, nHeadToEndSize);  
  139.         memcpy(pData+nHeadToEndSize,m_pQueueBase,nReadSize-nHeadToEndSize);  
  140.     }  
  141.     m_Head=(m_Head+nReadSize) % m_QueueSize;  
  142.     LeaveCriticalSection(&m_csRW);  
  143.     return nReadSize;  
  144. }  
  145.   
  146. // 当前队列缓存的数据大小  
  147. int CCircularQueue::Size()  
  148. {  
  149.     return (m_Tail-m_Head+m_QueueSize) % m_QueueSize;  
  150. }  
  151.   
  152. // 队列是否为空  
  153. bool CCircularQueue::IsEmpty()  
  154. {  
  155.     return (m_Head == m_Tail) ? true : false;  
  156. }  
  157.   
  158. // 队列是否满   
  159. bool CCircularQueue::IsFull()  
  160. {  
  161.     return (((m_Tail+1) % m_QueueSize) == m_Head) ? true : false;  
  162. }  
  163.   
  164. // 队列当前剩余空间大小  
  165. int CCircularQueue::RemainSize()  
  166. {  
  167.     return ((m_QueueSize-1)-Size());  
  168. }  
  169.   
  170. // 打印数据  
  171. void CCircularQueue::PrintData()  
  172. {  
  173.     int tempHead, tempTail;  
  174.     tempHead = m_Head;  
  175.     tempTail = m_Tail;  
  176.     printf("************************************************\n");  
  177.     printf("CirualarQueue Data:");  
  178.     while(tempHead != tempTail)  
  179.     {  
  180.         printf("0x%02x ", m_pQueueBase[tempHead]);  
  181.         tempHead=(tempHead+1) % m_QueueSize;  
  182.     }  
  183.     printf("\n");  
  184.     printf("************************************************\n");  
  185. }  
  186.   
  187. // 重新调整队列大小  
  188. bool CCircularQueue::Resize(int nQueueSize)  
  189. {  
  190.     unsigned char *pNewQueue = NULL;  
  191.     // 申请新的队列空间  
  192.     pNewQueue = new unsigned char[nQueueSize];  
  193.     if(pNewQueue == NULL) // 申请内存失败  
  194.         return false;  
  195.     // 将队列原有数据拷贝到新队列中  
  196.     int len = PopFront(pNewQueue,nQueueSize);  
  197.     // 释放原来队列空间  
  198.     if(m_pQueueBase)  
  199.     {  
  200.         delete[] m_pQueueBase;  
  201.         m_pQueueBase = NULL;  
  202.     }  
  203.     // 使用新的队列空间  
  204.     m_pQueueBase = pNewQueue;  
  205.     m_QueueSize = nQueueSize;  
  206.     m_Head = 0;  
  207.     m_Tail = len;  
  208.     return true;  
  209. }  
0
0
 
 


乒乓缓存(Ping-Pong Buffer)是一种双缓冲区结构,用于在读写操作之间实现数据缓存。在Verilog中,你可以通过使用两个存储器(如RAM)和一些控制逻辑来实现乒乓缓存。 下面是一个简单的Verilog代码示例,展示了如何实现乒乓缓存: ```verilog module PingPongBuffer ( input wire clk, // 时钟信号 input wire reset, // 复位信号 input wire write_en, // 写使能信号 input wire read_en, // 读使能信号 input wire data_in, // 写入数据 output wire data_out // 输出数据 ); reg [7:0] buffer1; // 存储器1,用于缓存数据 reg [7:0] buffer2; // 存储器2,用于缓存数据 reg select; // 选择信号,用于切换存储器 reg [7:0] output_data; // 输出数据 always @(posedge clk or posedge reset) begin if (reset) begin buffer1 <= 8'b0; // 复位缓存1 buffer2 <= 8'b0; // 复位缓存2 select <= 1'b0; // 设置初始选择为缓存1 output_data <= 8'b0; end else begin if (write_en) begin if (select) begin buffer2 <= data_in; // 写入数据缓存2 end else begin buffer1 <= data_in; // 写入数据缓存1 end end if (read_en) begin if (select) begin output_data <= buffer1; // 输出缓存1的数据 end else begin output_data <= buffer2; // 输出缓存2的数据 end end select <= ~select; // 切换存储器 end end assign data_out = output_data; // 输出数据 endmodule ``` 在这个示例中,我们使用了两个8位宽度的存储器(buffer1和buffer2)来实现乒乓缓存。在时钟上升沿触发的时候,根据写使能信号(write_en)和读使能信号(read_en),切换存储器并进行数据的读写操作。选择信号(select)用于切换当前使用的存储器。最后,输出数据(data_out)根据选择信号输出缓存中的数据。 请注意,这只是一个简单的示例,实际应用中可能需要更复杂的控制逻辑和数据宽度。此外,根据具体的需求,你可能还需要添加一些额外的功能,如错误检测、缓存满/空状态等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值