<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    線程安全的環形緩沖區實現

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    來源:http://blog.csdn.net/lezhiyong
        應用背景:線程1將每次數量不一的音頻采樣點(PCM音頻數據)寫入環形緩沖區,線程2每次取固定數量采樣點送音頻編碼器,線程1線程2在平均時間內的讀寫數據量相等。(倒入桶中的水量有時大有時小,但每次取一瓢喝:)
       該環形緩沖區借鑒CoolPlayer音頻播放器中的環形緩沖區代碼實現,在讀寫操作函數中加了鎖,允許多線程同時操作。CPs_CircleBuffer基于內存段的讀寫,比用模板實現的環形緩沖隊列適用的數據類型更廣些, CPs_CircleBuffer修改成C++中基于對象的實現,加上詳細注釋,m_csCircleBuffer鎖變量為自用的lock類型(將CRITICAL_SECTION封裝起來),調用lock()加鎖,調用unlock()解鎖。使用效果良好,分享出來。

    CPs_CircleBuffer環形緩沖還不具備當待寫數據量超出空余緩沖時自動分配內存的功能,這個將在后續進行優化。

    CPs_CircleBuffer使用步驟:

     

    [cpp] view plaincopy
    1. 1、創建對象  
    2. CPs_CircleBuffer* m_pCircleBuffer;  
    3. m_pCircleBuffer = new CPs_CircleBuffer(bufsize);  
    4. 2、寫  
    5. if (m_pCircleBuffer->GetFreeSize() < CIC_READCHUNKSIZE)  
    6.  {  
    7.      Sleep(20);  
    8.      continue;  
    9.  }  
    10. m_pCircleBuffer->Write(internetbuffer.lpvBuffer,internetbuffer.dwBufferLength);  
    11. 3、讀  
    12. m_pCircleBuffer->Read(pDestBuffer,iBytesToRead, piBytesRead);  
    13.    
    14. 4、其他調用  
    15. if(m_pCircleBuffer->IsComplete())  
    16.     break;          
    17. iUsedSpace =m_pCircleBuffer->GetUsedSize();  
    18. m_pCircleBuffer->SetComplete();  

     

    CPs_CircleBuffer修改為類的定義:

    [cpp] view plaincopy
    1. class  CPs_CircleBuffer  
    2. {  
    3. public:  
    4.        CPs_CircleBuffer(const unsigned int iBufferSize);  
    5.        ~CPs_CircleBuffer();  
    6. public:  
    7.         // Public functions  
    8.         void  Uninitialise();  
    9.         void  Write(const void* pSourceBuffer, const unsigned int iNumBytes);  
    10.         bool  Read(void* pDestBuffer, const size_t iBytesToRead, size_t* pbBytesRead);  
    11.         void  Flush();  
    12.         unsigned int GetUsedSize();  
    13.         unsigned int GetFreeSize();  
    14.         void  SetComplete();  
    15.         bool  IsComplete();  
    16.   
    17. private:         
    18.         unsigned char*  m_pBuffer;  
    19.         unsigned int    m_iBufferSize;  
    20.         unsigned int    m_iReadCursor;  
    21.         unsigned int    m_iWriteCursor;  
    22.         HANDLE          m_evtDataAvailable;  
    23.         Vlock           m_csCircleBuffer;  
    24.         bool            m_bComplete;        
    25. };  

    CPs_CircleBuffer修改為類的實現:

    [cpp] view plaincopy
    1. #define CIC_WAITTIMEOUT  3000  
    2.   
    3. CPs_CircleBuffer::CPs_CircleBuffer(const unsigned int iBufferSize)  
    4. {  
    5.     m_iBufferSize = iBufferSize;  
    6.     m_pBuffer = (unsigned char*)malloc(iBufferSize);  
    7.     m_iReadCursor = 0;  
    8.     m_iWriteCursor = 0;  
    9.     m_bComplete = false;  
    10.     m_evtDataAvailable = CreateEvent(NULL, FALSE, FALSE, NULL);  
    11. }  
    12.   
    13. CPs_CircleBuffer::~CPs_CircleBuffer()  
    14. {  
    15.     Uninitialise();  
    16. }  
    17.   
    18. // Public functions  
    19. void CPs_CircleBuffer::Uninitialise()//沒有必要public這個接口函數,long120817  
    20. {  
    21.     CloseHandle(m_evtDataAvailable);  
    22.     free(m_pBuffer);  
    23. }  
    24.   
    25. //Write前一定要調用m_pCircleBuffer->GetFreeSize(),如果FreeSize不夠需要等待,long120817  
    26.   
    27. void  CPs_CircleBuffer::Write(const void* _pSourceBuffer, const unsigned int _iNumBytes)  
    28. {  
    29.     unsigned int iBytesToWrite = _iNumBytes;  
    30.     unsigned char* pSourceReadCursor = (unsigned char*)_pSourceBuffer;  
    31.   
    32.     //CP_ASSERT(iBytesToWrite <= GetFreeSize());//修改為沒有足夠空間就返回,write前一定要加GetFreeSize判斷,否則進入到這里相當于丟掉數據,         // long120817  
    33.     if (iBytesToWrite > GetFreeSize())  
    34.     {  
    35.         return;  
    36.     }  
    37.     _ASSERT(m_bComplete == false);  
    38.   
    39.     m_csCircleBuffer.Lock();  
    40.   
    41.     if (m_iWriteCursor >= m_iReadCursor)  
    42.     {  
    43.         //              0                                            m_iBufferSize  
    44.         //              |-----------------|===========|--------------|  
    45.         //                                pR->        pW->   
    46.         // 計算尾部可寫空間iChunkSize,long120817  
    47.         unsigned int iChunkSize = m_iBufferSize - m_iWriteCursor;  
    48.   
    49.         if (iChunkSize > iBytesToWrite)  
    50.         {  
    51.             iChunkSize = iBytesToWrite;  
    52.         }  
    53.   
    54.         // Copy the data  
    55.         memcpy(m_pBuffer + m_iWriteCursor,pSourceReadCursor, iChunkSize);  
    56.   
    57.         pSourceReadCursor += iChunkSize;  
    58.   
    59.         iBytesToWrite -= iChunkSize;  
    60.   
    61.         // 更新m_iWriteCursor  
    62.         m_iWriteCursor += iChunkSize;  
    63.   
    64.         if (m_iWriteCursor >= m_iBufferSize)//如果m_iWriteCursor已經到達末尾  
    65.             m_iWriteCursor -= m_iBufferSize;//返回到起點0位置,long120817  
    66.   
    67.     }  
    68.   
    69.     //剩余數據從Buffer起始位置開始寫  
    70.     if (iBytesToWrite)  
    71.     {  
    72.         memcpy(m_pBuffer + m_iWriteCursor,pSourceReadCursor, iBytesToWrite);  
    73.         m_iWriteCursor += iBytesToWrite;  
    74.         _ASSERT(m_iWriteCursor < m_iBufferSize);//這個斷言沒什么意思,應該_ASSERT(m_iWriteCursor <= m_iReadCursor);long20120817  
    75.     }  
    76.   
    77.     SetEvent(m_evtDataAvailable);//設置數據寫好信號量  
    78.   
    79.     m_csCircleBuffer.UnLock();  
    80. }  
    81.   
    82. bool  CPs_CircleBuffer::Read(void* pDestBuffer, const size_t _iBytesToRead, size_t* pbBytesRead)  
    83. {  
    84.     size_t iBytesToRead = _iBytesToRead;  
    85.     size_t iBytesRead = 0;  
    86.     DWORD dwWaitResult;  
    87.     bool bComplete = false;  
    88.   
    89.     while (iBytesToRead > 0 && bComplete == false)  
    90.     {  
    91.         dwWaitResult = WaitForSingleObject(m_evtDataAvailable, CIC_WAITTIMEOUT);//等待數據寫好,long120817  
    92.   
    93.         if (dwWaitResult == WAIT_TIMEOUT)  
    94.         {  
    95.             //TRACE_INFO2("Circle buffer - did not fill in time!");  
    96.             *pbBytesRead = iBytesRead;  
    97.             return FALSE;//等待超時則返回  
    98.         }  
    99.   
    100.         m_csCircleBuffer.Lock();  
    101.   
    102.         if (m_iReadCursor > m_iWriteCursor)  
    103.         {  
    104.             //              0                                                    m_iBufferSize  
    105.             //              |=================|-----|===========================|  
    106.             //                                pW->  pR->   
    107.             unsigned int iChunkSize = m_iBufferSize - m_iReadCursor;  
    108.   
    109.             if (iChunkSize > iBytesToRead)  
    110.                 iChunkSize = (unsigned int)iBytesToRead;  
    111.   
    112.             //讀取操作  
    113.             memcpy((unsigned char*)pDestBuffer + iBytesRead,m_pBuffer + m_iReadCursor,iChunkSize);  
    114.   
    115.             iBytesRead += iChunkSize;  
    116.             iBytesToRead -= iChunkSize;  
    117.   
    118.             m_iReadCursor += iChunkSize;  
    119.   
    120.             if (m_iReadCursor >= m_iBufferSize)//如果m_iReadCursor已經到達末尾  
    121.                 m_iReadCursor -= m_iBufferSize;//返回到起點0位置,long120817  
    122.         }  
    123.   
    124.         if (iBytesToRead && m_iReadCursor < m_iWriteCursor)  
    125.         {  
    126.             unsigned int iChunkSize = m_iWriteCursor - m_iReadCursor;  
    127.   
    128.             if (iChunkSize > iBytesToRead)  
    129.                 iChunkSize = (unsigned int)iBytesToRead;  
    130.   
    131.             //讀取操作  
    132.             memcpy((unsigned char*)pDestBuffer + iBytesRead,m_pBuffer + m_iReadCursor,iChunkSize);  
    133.   
    134.             iBytesRead += iChunkSize;  
    135.             iBytesToRead -= iChunkSize;  
    136.             m_iReadCursor += iChunkSize;  
    137.         }  
    138.   
    139.         //如果有更多的數據要寫  
    140.         if (m_iReadCursor == m_iWriteCursor)  
    141.         {  
    142.             if (m_bComplete)//跳出下一個while循環,該值通過SetComplete()設置,此邏輯什么意思?long120817  
    143.                 bComplete = true;  
    144.         }  
    145.         else//還有數據可以讀,SetEvent,在下一個while循環開始可以不用再等待,long120817  
    146.             SetEvent(m_evtDataAvailable);  
    147.   
    148.         m_csCircleBuffer.UnLock();  
    149.     }  
    150.   
    151.     *pbBytesRead = iBytesRead;  
    152.   
    153.     return bComplete ? false : true;  
    154.   
    155. }  
    156. //  0                                                m_iBufferSize  
    157. //  |------------------------------------------------|  
    158. //  pR  
    159. //  pW  
    160. //讀寫指針歸零  
    161. void  CPs_CircleBuffer::Flush()  
    162. {  
    163.     m_csCircleBuffer.Lock();  
    164.     m_iReadCursor = 0;  
    165.     m_iWriteCursor = 0;  
    166.     m_csCircleBuffer.UnLock();  
    167.   
    168. }  
    169. //獲取已經寫的內存  
    170. unsigned int CPs_CircleBuffer::GetUsedSize()  
    171. {  
    172.      return m_iBufferSize - GetFreeSize();  
    173.   
    174. }  
    175.   
    176.   
    177. unsigned int CPs_CircleBuffer::GetFreeSize()  
    178. {  
    179.     unsigned int iNumBytesFree;  
    180.   
    181.     m_csCircleBuffer.Lock();  
    182.   
    183.     if (m_iWriteCursor < m_iReadCursor)  
    184.     {  
    185.         //              0                                                    m_iBufferSize  
    186.         //              |=================|-----|===========================|  
    187.         //                                pW->  pR->   
    188.         iNumBytesFree = (m_iReadCursor - 1) - m_iWriteCursor;  
    189.     }  
    190.     else if (m_iWriteCursor == m_iReadCursor)  
    191.     {  
    192.         iNumBytesFree = m_iBufferSize;  
    193.     }  
    194.     else  
    195.     {  
    196.         //              0                                                    m_iBufferSize  
    197.         //              |-----------------|=====|---------------------------|  
    198.         //                                pR->   pW->   
    199.         iNumBytesFree = (m_iReadCursor - 1) + (m_iBufferSize - m_iWriteCursor);  
    200.     }  
    201.   
    202.     m_csCircleBuffer.UnLock();  
    203.   
    204.     return iNumBytesFree;  
    205.   
    206. }  
    207. //該函數什么時候調用?long120817  
    208. void  CPs_CircleBuffer::SetComplete()  
    209. {  
    210.     m_csCircleBuffer.Lock();  
    211.     m_bComplete = true;  
    212.     SetEvent(m_evtDataAvailable);  
    213.     m_csCircleBuffer.UnLock();  
    214. }  

     

    附自動初始化和摧毀的鎖對象Vlock的實現:

    [cpp] view plaincopy
      1. #ifdef WIN32  
      2. #include <windows.h>  
      3.   
      4. #define  V_MUTEX            CRITICAL_SECTION //利用臨界區實現的鎖變量  
      5. #define  V_MUTEX_INIT(m)        InitializeCriticalSection(m)  
      6. #define  V_MUTEX_LOCK(m)        EnterCriticalSection(m)  
      7. #define  V_MUTEX_UNLOCK(m)      LeaveCriticalSection(m)  
      8. #define  V_MUTEX_DESTORY(m)     DeleteCriticalSection(m)  
      9.   
      10. #else  
      11.   
      12. #define  V_MUTEX                pthread_mutex_t  
      13. #define  V_MUTEX_INIT(m)        pthread_mutex_init(m,NULL)  
      14. #define  V_MUTEX_LOCK(m)        pthread_mutex_Lock(m)  
      15. #define  V_MUTEX_UNLOCK(m)      pthread_mutex_unLock(m)  
      16. #define  V_MUTEX_DESTORY(m)     pthread_mutex_destroy(m)  
      17.   
      18. #endif  
      19.   
      20.   
      21. class  Vlock  
      22. {  
      23. public:  
      24.     Vlock(void)  
      25.     {  
      26.         V_MUTEX_INIT(&m_Lock);  
      27.     }  
      28.     ~Vlock(void)  
      29.     {  
      30.         V_MUTEX_DESTORY(&m_Lock);  
      31.     }  
      32. public:  
      33.     void Lock(){V_MUTEX_LOCK(&m_Lock);}  
      34.     void UnLock(){V_MUTEX_UNLOCK(&m_Lock);}  
      35. private:  
      36.     V_MUTEX m_Lock;  
      37. };  
    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全