精华内容
下载资源
问答
  • ringbuf无锁单生产者单消费者(SPSC)FIFO环形缓冲区,可直接访问内部数据。 概述RingBuffer是最初的结构ringbuf无锁单生产者单消费者(SPSC)FIFO环形缓冲区,可直接访问内部数据。 概述RingBuffer是代表环形缓冲区...
  • ringbuf

    2018-09-03 10:31:46
    读写安全的环状buffer。 源码链接:... #ifndef _NAIVE_RINGBUF_H_ #define _NAIVE_RINGBUF_H_ #include <cstring> #include <cstdint> ...

    读写安全的环状buffer。

    源码链接:https://github.com/SaberMqd/naive/blob/master/include/naive/ring_buffer.h

    #ifndef _NAIVE_RINGBUF_H_
    #define _NAIVE_RINGBUF_H_
    
    #include <cstring>
    #include <cstdint>
    
    #include "safe_delete.h"
    #include "base_constructor.h"
    
    namespace naive {
    
    template <typename T>
    class RingBuf {
    
    public:
    
    	explicit RingBuf(uint32_t len):
    		_len(len+1),_beg(0),_end(0) {
    		_buf = new T[_len]{ 0 };
    	}
    
    	void Reset() {
    		_beg = 0;
    		_end = 0;
    		memset(_buf, 0, _len * sizeof(T));
    	}
    
    	bool Push(const T* in_buf, uint32_t len) {
    		if (len > GetSpareLen()) {
    			return false;
    		}
    		if (_beg > _end) {
    			if (_beg - _end ==1){
    				return false;
    			}
    			_end += len;
    			memcpy(_buf + _end, in_buf, len * sizeof(T));
    		} else {//_beg <= _end
    			uint32_t afterLen = _len - _end;
    			if (afterLen > len) {//
    				memcpy(_buf + _end, in_buf, len * sizeof(T));
    				_end += len;
    			} else {
    				memcpy(_buf + _end, in_buf, afterLen * sizeof(T));
    				uint32_t frontLen = len - afterLen;
    				_end = frontLen ;//
    				memcpy(_buf, in_buf + afterLen, frontLen * sizeof(T));
    			}
    		}
    		return true;
    	}
    
    	T* Pop(uint32_t len) {
    		if ((_len -1 - GetSpareLen()) < len) {//
    			return nullptr;
    		}
    		T* tempBuf = new T[len];
    		if (_beg > _end) {
    			uint32_t afterLen = _len - _beg - 1;
    			if (afterLen > len) {//
    				memcpy(tempBuf, _buf + _beg, len * sizeof(T));
    				_beg += len;
    				return tempBuf;
    			}
    			memcpy(tempBuf, _buf + _beg, afterLen * sizeof(T));
    			uint32_t frontLen = len - afterLen;
    			memcpy(tempBuf + afterLen, _buf, frontLen * sizeof(T));
    			_beg = frontLen;
    		} else {
    			memcpy(tempBuf, _buf + _beg, len * sizeof(T));
    			_beg += len;
    		}
    		return tempBuf;
    	}
    
    	bool Pop(T* in_buf, uint32_t len) {		
    		if ((_len - 1 - GetSpareLen()) < len) {//
    			return false;
    		}
    		if (_beg > _end) {
    			uint32_t afterLen = _len - _beg;
    			if (afterLen > len) {//
    				memcpy(in_buf, _buf + _beg, len * sizeof(T));
    				_beg += len;
    				return true;
    			}
    			memcpy(in_buf, _buf + _beg, afterLen * sizeof(T));
    			uint32_t frontLen = len - afterLen;
    			memcpy(in_buf + afterLen, _buf, frontLen * sizeof(T));
    			_beg = frontLen;
    		}
    		else {
    			memcpy(in_buf, _buf + _beg, len * sizeof(T));
    			_beg += len;
    		}
    		return true;
    	}
    
    	uint32_t TryPop(T* in_buf, uint32_t len) {
    		const uint32_t contentLen = (_len - 1 - GetSpareLen());//
    		if (contentLen < len) {
    			Pop(in_buf, contentLen);
    			return contentLen;		
    		}
    		Pop(in_buf, len);
    		return len;
    	}
    
    	uint32_t Size() {
    		return _len - 1 - GetSpareLen();
    	}
    
    	bool PushBack(const T* in_buf, uint32_t len) {
    		if (len > GetSpareLen()) {
    			return false;
    		}
    		if (_beg > _end) {
    			_beg -= len;
    			memcpy(_buf + _beg, in_buf, len * sizeof(T));
    		}else {//_beg<=_end
    			if (_beg >= len) {
    				_beg -= len;
    				memcpy(_buf + _beg, in_buf, len * sizeof(T));
    			}else {
    				uint32_t frontLen = len - _beg;
    				memcpy(_buf + (_len - frontLen), in_buf, frontLen * sizeof(T));
    				memcpy(_buf, in_buf + _beg, _beg * sizeof(T));//
    				_beg = _len - frontLen;
    			}
    		}
    		return true;
    	}
    
    	bool PopBack(T* in_buf, uint32_t len) {
    		if ((_len - 1 - GetSpareLen()) < len) {//
    			return false;
    		}
    		if (_beg > _end) {
    			if (len <= _end) {
    				memcpy(in_buf, _buf + (_end - len), len * sizeof(T));
    				_end -= len;
    				return true;
    			}
    			uint32_t frontLen = len - _end;
    			memcpy(in_buf, _buf + (_len - frontLen), frontLen * sizeof(T));
    			memcpy(in_buf + frontLen, _buf, _end * sizeof(T));
    			_end = (_len - frontLen);
    		}else {
    			if (_beg == _end) {
    				return false;
    			}
    			memcpy(in_buf, _buf + (_end - len), len * sizeof(T));//
    			_end -= len;
    		}
    		return true;
    	}
    
    	uint32_t TryPopBack(T* in_buf, uint32_t len) {
    		const uint32_t contentLen = (_len - 1 - GetSpareLen());//
    		if (contentLen < len) {
    			PopBack(in_buf, contentLen);
    			return contentLen;
    		}
    		PopBack(in_buf, len);
    		return len;
    	}
    
    	~RingBuf() {
    		SafeDeleteArray(_buf);
    	}
    
    private:
    
    	uint32_t _beg;
    	uint32_t _end;
    	uint32_t _len;
    	T*      _buf;
    
    	uint32_t GetSpareLen() const {
    		if (_beg < _end){
    			return (_len - (_end - _beg) - 1);
    		} else if (_beg > _end) {
    			return (_beg - _end - 1);
    		} else {
    			return _len - 1;//
    		}
    	}
    	DISALLOW_COPY_AND_ASSIGN(RingBuf)
    };
    
    }
    
    #endif

     

    展开全文
  • 纯C ringbuf源码和示例

    2019-03-13 08:06:25
    包含一个.c一个.h的源码,另外有一个test文件,实际使用时,取出用的变量必须是全局变量,原因未知,有知道的给解释一下
  • ringbuf_Ringbuf_源码

    2021-10-04 10:51:25
    环形缓冲,用于存储数据,保证两个任务读取速度能赶的上写入速度,防止丢包
  • nrf_ringbuf

    2020-12-24 17:57:46
    nrf_ringbuf_init(&m_log_push_ringbuf); 上面一句话干了啥? 1--参数是啥 没有参数 goto只看到前面这句话 风格很nordic 如下 也就是一股脑出来很多static东西!! NRF_RINGBUF_DEF(m_log_push_ringbuf,...

        nrf_ringbuf_init(&m_log_push_ringbuf);
        上面一句话干了啥?
        1--参数是啥
        没有参数 goto只看到前面这句话 风格很nordic
        如下
        也就是一股脑出来很多static东西!!
        
        NRF_RINGBUF_DEF(m_log_push_ringbuf, NRF_LOG_STR_PUSH_BUFFER_SIZE);
        
        #define NRF_RINGBUF_DEF(_name, _size)                                         \
        STATIC_ASSERT(IS_POWER_OF_TWO(_size));                                    \
        static uint8_t CONCAT_2(_name,_buf)[_size];                               \
        static nrf_ringbuf_cb_t CONCAT_2(_name,_cb);                              \
        static const nrf_ringbuf_t _name = {                                      \
                .p_buffer = CONCAT_2(_name,_buf),                                 \
                .bufsize_mask = _size - 1,                                        \
                .p_cb         = &CONCAT_2(_name,_cb),                             \
        }
        
        
        
    typedef struct
    {
        nrf_atomic_flag_t   wr_flag;   //!< Protection flag.
        nrf_atomic_flag_t   rd_flag;   //!< Protection flag.
        uint32_t            wr_idx;     //!< Write index (updated when putting).
        uint32_t            tmp_wr_idx; //!< Temporary write index (updated when allocating).
        uint32_t            rd_idx;     //!< Read index (updated when freeing).
        uint32_t            tmp_rd_idx; //!< Temporary read index (updated when getting).
    } nrf_ringbuf_cb_t;

    /**
     * @brief Ring buffer instance structure.
     * */
    typedef struct
    {
        uint8_t           * p_buffer;     //!< Pointer to the memory used by the ring buffer.
        uint32_t            bufsize_mask; //!< Buffer size mask (buffer size must be a power of 2).
        nrf_ringbuf_cb_t  * p_cb;         //!< Pointer to the instance control block.
    } nrf_ringbuf_t;

    2--上面这句话 就是memset


    nrf_ringbuf.c

    继续看

     

    看不懂 WHY 只有一个函数呢

     

    自己成功的测试 模型

    #include "gsdk_task.h"
    #include "gsdk_cmd.h"
    #include "gProtocol.h"
    
    #include "freertos.h"
    #include "task.h"
    
    
    NRF_RINGBUF_DEF(m_sendData_ringbuf, NRF_LOG_STR_PUSH_BUFFER_SIZE);
    nrf_ringbuf_t const * psendData_ringbuf = &m_sendData_ringbuf;
    static TaskHandle_t m_send_thread;                               
    static TaskHandle_t m_recv_thread;                             
    
    static void sendDataTask(void *pvParameters) 
    {
        int32_t tempLength = 0;
        uint8_t tempData  = 'A';
        uint8_t data[2]  = {0};
        size_t ssize = 1+1; 
        uint8_t * p_dst = data;
        //gfifotx.init();
        nrf_ringbuf_init(&m_sendData_ringbuf);
        ((void)(pvParameters));
        for (; ;) 
        {
            //vTaskSuspend(NULL); // Suspend myself
            vTaskDelay(2000);
            //tempLength = gfifotx.readone(&tempData);
            //if (tempLength > 0) 
            //{
               //tcpWrite(tempData, tempLength);
               //  SHOWME
           // }
         
            if (nrf_ringbuf_alloc(&m_sendData_ringbuf, &p_dst, &ssize, true) == NRF_SUCCESS)
            {
                ret_code_t err;
                
                ++tempData;
                if(tempData == 'z') tempData = 'A';
                
                memcpy(p_dst, &tempData, ssize);
    
                //Terminate in case string was partial.
                p_dst[ssize - 1] = '\0';
    
                err = nrf_ringbuf_put(&m_sendData_ringbuf, ssize);
                ASSERT(err == NRF_SUCCESS);
                NRF_LOG_DEBUG("in%d----[%s]",ssize,p_dst);
                //Immediately free the space where string was put.
    //            err = nrf_ringbuf_free(&m_sendData_ringbuf, ssize);
    //            ASSERT(err == NRF_SUCCESS);
            }
              
    
    
        }
    }
    
    static void recvDataTask(void *pvParameters) 
    {
        //gfiforx.init();
        //gfifopag.init();
         ret_code_t err;
         uint8_t data[10]={0};
         uint8_t * pdata = data;
         size_t len=2;
        ((void)(pvParameters));
        for (; ;) 
        {
            //gProtocolLoop();
            vTaskDelay(1000);
            //ret_code_t nrf_ringbuf_get(nrf_ringbuf_t const * p_ringbuf, uint8_t * * pp_data, size_t * p_length, bool start);
    
           if(nrf_ringbuf_get(psendData_ringbuf ,&pdata , &len ,1  )== NRF_SUCCESS)
            {
               if(len)
               {               
                 NRF_LOG_DEBUG("out%d---[%s]",len,pdata);
                 nrf_ringbuf_free(&m_sendData_ringbuf, len);
               }
               else
                   NRF_LOG_DEBUG("out null");  
               
               len =2; // 因为 一旦成功 len会被修改 一般是修改为0
            }
            else
                SHOWME          
        }
    }
    
    
    
    
    void creatTXtask(void)
    {
        BaseType_t xReturned = xTaskCreate(sendDataTask,
                                           "sendDataTask",
                                           128,
                                           NULL,
                                           configMAX_PRIORITIES,
                                           &m_send_thread);
        if (xReturned != pdPASS)
        {
            NRF_LOG_ERROR("sendDataTask not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
        
        return ;
    }
    
    void creatRXtask(void)
    {
        BaseType_t xReturned = xTaskCreate(recvDataTask,
                                           "recvDataTask",
                                           128,
                                           NULL,
                                           configMAX_PRIORITIES,
                                           &m_recv_thread);
        if (xReturned != pdPASS)
        {
            NRF_LOG_ERROR("recvDataTask not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
        
        return ;
    }
    
    void creatSDKTask(void)
    {
        registerCmds();
        creatTXtask();
        creatRXtask();
    }
    

     

     

     

    继续研究 nrf的那个cpy的接口是做什么的呢?

    我想你知道了 既然做了FIFO那就是做了内存池 

    如果你每次 put get 还要自己用内存 memcpy只有的话 那就是带cpy的

    也就是前后都浪费内存!!!而我上面测试的 原理是 ** 也就是那内存池在用 不要自己携带内存!!

    所以 ** 应该会修改的!!!!

    再次测试

    #include "gsdk_task.h"
    #include "gsdk_cmd.h"
    #include "gProtocol.h"
    
    #include "freertos.h"
    #include "task.h"
    
    
    NRF_RINGBUF_DEF(m_sendData_ringbuf, NRF_LOG_STR_PUSH_BUFFER_SIZE);
    nrf_ringbuf_t const * psendData_ringbuf = &m_sendData_ringbuf;
    static TaskHandle_t m_send_thread;                               
    static TaskHandle_t m_recv_thread;                             
    
    static void sendDataTask(void *pvParameters) 
    {
        int32_t tempLength = 0;
        uint8_t tempData  = 'A';
        uint8_t data[2]  = {0};
        size_t ssize = 1+1; 
        uint8_t * p_dst = data;
        //gfifotx.init();
        nrf_ringbuf_init(&m_sendData_ringbuf);
        ((void)(pvParameters));
        for (; ;) 
        {
            //vTaskSuspend(NULL); // Suspend myself
            vTaskDelay(2000);
            //tempLength = gfifotx.readone(&tempData);
            //if (tempLength > 0) 
            //{
               //tcpWrite(tempData, tempLength);
               //  SHOWME
           // }
         
            if (nrf_ringbuf_alloc(&m_sendData_ringbuf, &p_dst, &ssize, true) == NRF_SUCCESS)
            {
                ret_code_t err;
                
                ++tempData;
                if(tempData == 'z') tempData = 'A';
                
                memcpy(p_dst, &tempData, ssize);
                p_dst[ssize - 1] = '\0';            //Terminate in case string was partial.
    
                err = nrf_ringbuf_put(&m_sendData_ringbuf, ssize);
                ASSERT(err == NRF_SUCCESS);
                NRF_LOG_DEBUG("in%d----[%s]--[%d-%d]",ssize,p_dst,data[0],data[1]);
            }
              
    
    
        }
    }
    
    static void recvDataTask(void *pvParameters) 
    {
        //gfiforx.init();
        //gfifopag.init();
         ret_code_t err;
    
    uint8_t data[2]  = {1,2};
    uint8_t * p_dst = data;
    p_dst[0]=3;
    p_dst[1]=4;
    NRF_LOG_DEBUG("[%d-%d]--[%d-%d]",data[0],data[1],p_dst[0],p_dst[1]);//3434
         uint8_t * pdata = NULL;
         size_t len=2;
        ((void)(pvParameters));
        for (; ;) 
        {
            //gProtocolLoop();
            vTaskDelay(1000);
            //ret_code_t nrf_ringbuf_get(nrf_ringbuf_t const * p_ringbuf, uint8_t * * pp_data, size_t * p_length, bool start);
    
           if(nrf_ringbuf_get(psendData_ringbuf ,&pdata , &len ,1  )== NRF_SUCCESS)
            {
               if(len)
               {               
                 NRF_LOG_DEBUG("out%d---[%s]--0X%08x",len,pdata,pdata);
                 nrf_ringbuf_free(&m_sendData_ringbuf, len);
               }
               else
                   NRF_LOG_DEBUG("out null");  
               
               len =2; // 因为 一旦成功 len会被修改 一般是修改为0
            }
            else
                SHOWME          
        }
    }
    
    
    
    
    void creatTXtask(void)
    {
        BaseType_t xReturned = xTaskCreate(sendDataTask,
                                           "sendDataTask",
                                           128,
                                           NULL,
                                           configMAX_PRIORITIES,
                                           &m_send_thread);
        if (xReturned != pdPASS)
        {
            NRF_LOG_ERROR("sendDataTask not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
        
        return ;
    }
    
    void creatRXtask(void)
    {
        BaseType_t xReturned = xTaskCreate(recvDataTask,
                                           "recvDataTask",
                                           128,
                                           NULL,
                                           configMAX_PRIORITIES,
                                           &m_recv_thread);
        if (xReturned != pdPASS)
        {
            NRF_LOG_ERROR("recvDataTask not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
        
        return ;
    }
    
    void creatSDKTask(void)
    {
        registerCmds();
        creatTXtask();
        creatRXtask();
    }
    

    果然 你看到 ** 指针的地址在奔跑!!!!就是内存池 所以 RX里面我不要自己数组了!!!!

    那么箭头能解释吗?WHY后面是 0 0 没有被赋值呢?看来也不需要内存!!!继续修改!!!

     

     

    果然!!OK

    代码如下 

    也即是PUT的时候 那个不是二级指针  那个nrf_ringbuf_alloc 参数进去 就是二级指针了 它会修改指针的指向的!!!!以前NULL也可以的!!

    出来的时候 指到内存次的一个地方 然后数据放进去即可

    #include "gsdk_task.h"
    #include "gsdk_cmd.h"
    #include "gProtocol.h"
    
    #include "freertos.h"
    #include "task.h"
    
    
    NRF_RINGBUF_DEF(m_sendData_ringbuf, NRF_LOG_STR_PUSH_BUFFER_SIZE);
    nrf_ringbuf_t const * psendData_ringbuf = &m_sendData_ringbuf;
    static TaskHandle_t m_send_thread;                               
    static TaskHandle_t m_recv_thread;                             
    
    static void sendDataTask(void *pvParameters) 
    {
        int32_t tempLength = 0;
        uint8_t tempData  = 'A';
        size_t ssize = 1+1; 
        uint8_t * p_dst = NULL;
        //gfifotx.init();
        nrf_ringbuf_init(&m_sendData_ringbuf);
        ((void)(pvParameters));
        for (; ;) 
        {
            //vTaskSuspend(NULL); // Suspend myself
            vTaskDelay(2000);
            //tempLength = gfifotx.readone(&tempData);
            //if (tempLength > 0) 
            //{
               //tcpWrite(tempData, tempLength);
               //  SHOWME
           // }
         
            if (nrf_ringbuf_alloc(&m_sendData_ringbuf, &p_dst, &ssize, true) == NRF_SUCCESS)
            {
                ret_code_t err;
                
                ++tempData;
                if(tempData == 'z') tempData = 'A';
                
                memcpy(p_dst, &tempData, ssize);
                p_dst[ssize - 1] = '\0';            //Terminate in case string was partial.
    
                err = nrf_ringbuf_put(&m_sendData_ringbuf, ssize);
                ASSERT(err == NRF_SUCCESS);
                NRF_LOG_DEBUG("in%d----[%s]--0X%08x",ssize,p_dst,p_dst);
            }
              
    
    
        }
    }
    
    static void recvDataTask(void *pvParameters) 
    {
        //gfiforx.init();
        //gfifopag.init();
         ret_code_t err;
    
    uint8_t data[2]  = {1,2};
    uint8_t * p_dst = data;
    p_dst[0]=3;
    p_dst[1]=4;
    NRF_LOG_DEBUG("[%d-%d]--[%d-%d]",data[0],data[1],p_dst[0],p_dst[1]);//3434
         uint8_t * pdata = NULL;
         size_t len=2;
        ((void)(pvParameters));
        for (; ;) 
        {
            //gProtocolLoop();
            vTaskDelay(1000);
            //ret_code_t nrf_ringbuf_get(nrf_ringbuf_t const * p_ringbuf, uint8_t * * pp_data, size_t * p_length, bool start);
    
           if(nrf_ringbuf_get(psendData_ringbuf ,&pdata , &len ,1  )== NRF_SUCCESS)
            {
               if(len)
               {               
                 NRF_LOG_DEBUG("out%d---[%s]--0X%08x",len,pdata,pdata);
                 nrf_ringbuf_free(&m_sendData_ringbuf, len);
               }
               else
                   NRF_LOG_DEBUG("out null");  
               
               len =2; // 因为 一旦成功 len会被修改 一般是修改为0
            }
            else
                SHOWME          
        }
    }
    
    
    
    
    void creatTXtask(void)
    {
        BaseType_t xReturned = xTaskCreate(sendDataTask,
                                           "sendDataTask",
                                           128,
                                           NULL,
                                           configMAX_PRIORITIES,
                                           &m_send_thread);
        if (xReturned != pdPASS)
        {
            NRF_LOG_ERROR("sendDataTask not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
        
        return ;
    }
    
    void creatRXtask(void)
    {
        BaseType_t xReturned = xTaskCreate(recvDataTask,
                                           "recvDataTask",
                                           128,
                                           NULL,
                                           configMAX_PRIORITIES,
                                           &m_recv_thread);
        if (xReturned != pdPASS)
        {
            NRF_LOG_ERROR("recvDataTask not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
        
        return ;
    }
    
    void creatSDKTask(void)
    {
        registerCmds();
        creatTXtask();
        creatRXtask();
    }
    

     

    展开全文
  • ringbuf:无锁环形缓冲区(MPSC)
  • ringbuf 开源代码,可以用于数据缓存使用
  • ringbuf-c.zip

    2021-07-16 17:11:16
    我自己实现的C语言版的无锁环形缓冲区ringbuffer。实现了指针环形存储和数据块环形存储。高可用,高性能。只有头文件。
  • 循环缓冲队列(ringbuf)

    2018-07-19 10:14:17
    #ifndef _RINGBUF_H_ #define _RINGBUF_H_ #define MAX_RINGBUF_SIZE_UART (170 + 1) #define RW_SIZE 8 typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32; typedef...
    #ifndef _RINGBUF_H_
    #define _RINGBUF_H_
    
    #define MAX_RINGBUF_SIZE_UART       (170 + 1)
    #define RW_SIZE 8
    
    typedef unsigned char   u8;
    typedef unsigned short  u16;
    typedef unsigned long   u32;
    
    typedef signed char err_t;
    
    #define FULL    -1
    #define EMPTY   -2
    #define FREE    -3
    #define USED    -4
    
    typedef struct {
        u32 head;   //出队列 - 写指针
        u32 tail;   //入队列 - 读指针
        u32 size;   //队列总长度
    
        u8 *space;  //队列空间
    } RINGBUF_Typedef;
    
    #define RINGBUF_IS_EMPTY(ringbuf)   ringbuf_is_empty(ringbuf)
    #define RINGBUF_IS_FULL(ringbuf)    ringbuf_is_full(ringbuf)
    #define RINGBUF_FREE(ringbuf)       ringbuf_free(ringbuf)
    #define RINGBUF_USED(ringbuf)       ringbuf_used(ringbuf)
    
    extern err_t ringbuf_init(RINGBUF_Typedef *ringbuf, u8 *space, u32 size);
    extern err_t ringbuf_push(RINGBUF_Typedef *ringbuf, u8 data);
    extern err_t ringbuf_pop(RINGBUF_Typedef *ringbuf, u8 *buf);
    extern err_t ringbuf_write(RINGBUF_Typedef *ringbuf, u8 *data, u32 size);
    extern err_t ringbuf_read(RINGBUF_Typedef *ringbuf, u8 *buf, u32 size);
    
    extern u32 ringbuf_is_empty(RINGBUF_Typedef *ringbuf);
    extern u32 ringbuf_is_full(RINGBUF_Typedef *ringbuf);
    extern u32 ringbuf_free(RINGBUF_Typedef *ringbuf);
    extern u32 ringbuf_used(RINGBUF_Typedef *ringbuf);
    
    #endif /* ringbuf.h */
    #include "ringbuf.h"
    
    RINGBUF_Typedef ringbuf_uart;
    u8 space_uart[MAX_RINGBUF_SIZE_UART];
    
    err_t ringbuf_init(RINGBUF_Typedef *ringbuf, u8 *space, u32 size)
    {
        ringbuf->head = 0;
        ringbuf->tail = 0;
        ringbuf->size = size;
        ringbuf->space = space;
    
        return 0;
    }
    
    err_t ringbuf_push(RINGBUF_Typedef *ringbuf, u8 data)
    {
        if (RINGBUF_IS_FULL(ringbuf)) {
    #ifdef DEBUG
            printf("ringbuf is full\n");
    #endif
            return FULL;
        }
    
        ringbuf->space[ringbuf->tail] = data;
        ringbuf->tail = (ringbuf->tail + 1) % ringbuf->size;
    
        if ((ringbuf->tail + 1) % ringbuf->size == ringbuf->head) {
    #ifdef DEBUG
            printf("ringbuf is full\n");
    #endif
        }
    
        return 0;
    }
    
    err_t ringbuf_pop(RINGBUF_Typedef *ringbuf, u8 *buf)
    {
        if (RINGBUF_IS_EMPTY(ringbuf)) {
    #ifdef DEBUG
            printf("ringbuf is empty\n");
    #endif
            return EMPTY;
        }
    
        *buf = ringbuf->space[ringbuf->head];
    
        ringbuf->head = (ringbuf->head + 1) % ringbuf->size;
    
        if (ringbuf->tail == ringbuf->head) {
    #ifdef DEBUG
            printf("ringbuf is empty\n");
    #endif
        }
    
        return 0;
    }
    
    err_t ringbuf_write(RINGBUF_Typedef *ringbuf, u8 *data, u32 size)
    {
        if (RINGBUF_FREE(ringbuf) < size) {
    #ifdef DEBUG
            printf("ringbuf is free < %d\n", size);
    #endif
            return FREE;
        }
    
        if (size > 0 && size <= RW_SIZE) {
            while (size --) {
                ringbuf_push(ringbuf, data[RW_SIZE - (size + 1)]);
            } 
        } else{
    #ifdef DEBUG
            printf("size is out of range\n");
    #endif
        }
    
        return 0;
    }
    
    err_t ringbuf_read(RINGBUF_Typedef *ringbuf, u8 *buf, u32 size)
    {
        if (RINGBUF_USED(ringbuf) < size) {
    #ifdef DEBUG
            printf("ringbuf is used < %d\n", size);
    #endif
            return USED;
        }
    
        if (size > 0 && size <= RW_SIZE) {
            while (size --) {
                ringbuf_pop(ringbuf, &buf[RW_SIZE - (size + 1)]);
            }
        } else {
    #ifdef DEBUG
            printf("size is out of range\n");
    #endif
        }
    
        return 0;
    }
    
    u32 ringbuf_is_empty(RINGBUF_Typedef *ringbuf)
    {
        return (ringbuf->head == ringbuf->tail);
    }
    
    u32 ringbuf_is_full(RINGBUF_Typedef *ringbuf)
    {
        return ((ringbuf->tail + 1) % ringbuf->size == ringbuf->head);
    }
    
    u32 ringbuf_free(RINGBUF_Typedef *ringbuf)
    {
        return ((ringbuf->head) > (ringbuf->tail) ? ((ringbuf->size) - (ringbuf->head) - (ringbuf->tail)) : ((ringbuf->size) - ((ringbuf->tail) - (ringbuf->head))));
    }
    
    u32 ringbuf_used(RINGBUF_Typedef *ringbuf)
    {
        return ((ringbuf->head) > (ringbuf->tail) ? ((ringbuf->size) - (ringbuf->head) + (ringbuf->tail)) : ((ringbuf->tail) - (ringbuf->head)));
    }
    展开全文
  • 嵌入式操作系统---核间通讯之RingBuf

    千次阅读 2018-04-07 10:44:41
    RingBuf又称为Circular Buffer,分为两种:分片形式的RingBuf、内存分割形式的RingBuf   2、特点 (1)由主核和从核定义好要进行数据共享内存区域(地址、大小); (2)环形缓冲区RingBuf用于两个核之间通讯, (3...

    前言

    两个核(分为主核和从核)之间进行通讯,一般使用共享内存的形式进行。

    核间通讯的机制,是以共享内存为媒介,利用核间中断来通知对方。通过核间对象的句柄进行具体的访问和操作;

    (1)多个核进行核间通讯时,首先由一个核创建一个核间对象,另外一个核通过名称或索引定位到该对象的句柄,从而对核间通讯对象进行操作。

    (2)核间中断来通知对方,采用“硬件信号量”对资源进行临界保护,再利用操作系统的信号量使得核间任务的通讯如同单核任务上的通讯。

     1、定义

    RingBuf又称为Circular Buffer,分为两种:分片形式的RingBuf、内存分割形式的RingBuf

     

    2、特点

    (1)由主核和从核定义好要进行数据共享内存区域(地址、大小);

    (2)环形缓冲区RingBuf用于两个核之间通讯,

    (3)环形缓冲区RingBuf的使用遵守严格的先进先出顺序进行处理。

    (4)环形缓冲区RingBuf是一项很好的技术,不用频繁的分配内存,而且在大多数情况下,内存的反复使用也使得我们能用更少的内存块做更多的事。

    (5)环形缓冲区RingBuf是一个先进先出的循环缓冲区,可以向通信程序提供对缓冲区的互斥访问。

    (6)环形缓冲区RingBuf是点对点的单向通讯;

     

    3、环形缓冲区的实现原理

    环形缓冲区通常有一个读指针和一个写指针。读指针指向环形缓冲区中可读的数据,写指针指向环形缓冲区中可写的缓冲区。通过移动读指针和写指针就可以实现缓冲区的数据读取和写入。

     

    由于Ringbuf具体实现上可以分为分片形式的RingBuf、内存分割形式的RingBuf;下面分别讲述这两种实现方式。

    (1)分片形式的RingBuf

    1)原理

    分片形式的RingBuf首先在内存堆中申请一块两核共享的内存区域,然后将这块内存区域分割成固定大小的分片,然后使用相应的内存管理结构进行管理。如下图所示:


    2)RingBuf管理结构体

    typedef struct

    {

        u32 WrIndex;//写入分片的索引值

             u32 RdIndex;//读出分片的索引值

             u8  *MemBufAddr;//内存堆的起始地址

             u32 MemShardingNum;//内存分片数量

             u32 MemShardingSize;//每个内存分片大小

             u32 InitDoneFlag;//初始化完成标志

             u32HandleSem;//RingBuf使用的信号量

             u32 SrcCpuID;//写入端CPU ID号

             u32 DstCpuID;//读取端CPU ID号

    }RingBufMan;

     

    3)RingBuf要实现的函数接口

    A.初始化RingBuf对象RingBufInit()

    由其中一个核根据Ringbuf配置参数创建RingBuf对象,创建完成后需要完成Ringbuf管理结构体的初始化;

    B.将新创建的RingBuf对象加入到共享对象管理结构体,便于集中管理(RingBufJoinShareQue());

    C.查找相应的RingBuf对象ID(根据写入端/读取端CPU ID号在共享对象队列中查找RingBufGetID());

    D.判空RingBufIsEmpty()

    (ringBufMan-> WrIndex == ringBufMan-> RdIndex)

    E.判满RingBufIsFull()

    Tmp = ringBufMan-> WrIndex - ringBufMan-> RdIndex + 1

    (Tmp ==0 || Tmp == ringBufMan-> MemShardingNum)

    F.写入RingBufPut(RingBufMan*,u8 *BufAddr,u32 LenPut)

    pWr=ringBufMan->MemBufAddr+ringBufMan->WrIndex*ringBufMan->MemShardingSize;

    *(u32*)pWr = LenPut;

    memcpy((void*)( pWr+sizeof(u32) ),(void*)pBufAddr, LenPut);

    ringBufMan->WrIndex= (ringBufMan->WrIndex+1)% ringBufMan-> MemShardingNum;

     

    E.读取RingBufGut(RingBufMan*,u8 *BufAddr,u32 LenMaxGut,u8 *Len)

    pRd=ringBufMan->MemBufAddr+ringBufMan->RdIndex*ringBufMan->MemShardingSize;

    LenValid= *(u32*)pRd;

    Lencp=min(LenValid, LenMaxGut);

    memcpy((void*)BufAddr ,(void*)( pWr+sizeof(u32) ), Lencp);

    ringBufMan->RdIndex= (ringBufMan->RdIndex+1)% ringBufMan-> MemShardingNum;

    *Len= Lencp;

    当然,这里的Put\Get只是一个分片的读写,至于一包数据写时需要多少个分片,读时需要读完几个分片,需要根据数据包的大小具体的计算;

    (2)内存分割形式的RingBuf


    typedef struct { 

            unsigned char *buffer; 

            unsigned int size; 

            unsigned int in; 

            unsigned int out; 

            spinlock_t *lock; 

    }kfifo ;

    其中buffer指向存放数据的缓冲区,size是缓冲区的大小,in是写指针下标,out是读指针下标,lock是加到struct kfifo上的自旋锁(上面说不加锁不是这里的锁),防止多个进程并发访问此数据结构。当in==out时,说明缓冲区为空;当(in-out)==size时,说明缓冲区已满。

                                                            

        注:我们保有对应的读写指针,当第一批数据(蓝色)完成,第二批数据(红色)会根据当前的写指针位置继续我们的数据操作,当达到最大的Buffer_Size时,会重新回到Buffer的开始端。

    4、多个应用读写RingBuf情况下的处理

    (1)互斥锁

    在通常情况下,环形缓冲区的读用户仅仅会影响读指针,而写用户仅仅会影响写指针。如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以保证数据的正确性。如果有多个读写用户访问环形缓冲区,那么必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。

    互斥锁可以采用两个核共享的自旋锁来实现,哪个核等到锁,哪个核有权对RingBuf资源进行读写操作。

    (2)使用异步消息队列AsyncMsgQ

    AsyncMsgQ是基于RingBuf来实现的,用于主从核内多个线程之间数据交换。

    1)  AsyncMsgQ是基于RingBuf,实现了两个核之间两个线程之间的通讯,通过MsgAttr来表示消息来自哪个核的哪个线程ID;

    2)  可以将AsyncMsgQ与线程ID进行绑定,并在收发端设置一个守护线程,根据接收到的MsgAttr中的目的线程ID进行消息分发,进而将消息分发到不同的AsyncMsgQ队列中,一包消息接收完成之后可以调用AsyncMsgQ已经挂载好的回调函数,进一步对消息进行解析或使用信号量将消息发送到任务。

    多个应用程序读写还可以在RingBuf的基础上实现消息队列,消息队列通过管理结构体记录消息的port,保证写入到ringbuf时数据写入/读取的原子性。

    除了保证写入/读取的原子性操作,还有一个问题就是,若核1中有多个应用程序以临界访问的形式向RingBuf中写数据,那么另外一个核0如何知道是哪个应用程序写入到RingBuf?

    为了实现Ringbuf这种携带数据的功能,我们可以对写入RingBuf的每一条消息进行标识,例如,在每一包消息的头部增加一个数据结构用于表示该报数据来自哪个核的哪个应用,又去往哪个核的哪个应用,包含了多少数据,使用了多少分片等等信息。

    typedef struct

    {

             u32 MsgShardingNum;//本消息包占用的Ringbuf分片数

             u32 MsgLen;//本消息包的长度

             u32 SrcCpuID;//源端CPU ID号

             u32 DstCpuID;//目的端CPU ID号

             u32 SrcThreadID;//源端线程ID

             u32 DstThreadID;//目的端线程ID

            

    }MsgAttr;

    同时为了表示每个分片所属消息ID及有效数据大小,还涉及了以下结构:
    typedef struct

    {

             u16ShardingID;//分片ID,用于识别是第几个分片

             u16ShardingLen;//分片有效数据长度

    }ShardingAttr;

    RingBuf在内存中的分布如下:


    AsyncMsgQ主要的接口函数:
    1)初始化AsyncMsgQ

    2)  AsyncMsgQ通道申请

    申请未被使用的AsyncMsgQ通道,并同ThreadID绑定,同时,设置相应的消息接收完成回调函数

    3)  数据发送

    计算发送数据所需要的RingBuf分片数,将数据拷贝到分片,并设置相应的MsgAttr\ ShardingAttr

    4)数据接收

    包括轮询接收,信号量阻塞接收,根据接收到的MsgAttr进行数据解析和分发;

    参考:

    https://en.wikipedia.org/wiki/Circular_buffer


    展开全文
  • ringbuf.js Web的线程安全免等待单消费者单生产者环形缓冲区以及一些实用程序。 该库的主要文件: js/ringbuf.js :基本数据结构,实现环形缓冲区。 有意对此发表了强烈评论。 js/audioqueue.js :包装音频数据...
  • ringBuf源码文件

    2010-02-10 21:02:52
    源码文件:嵌入式领域的ringBuf数据结构和算法的实现。是嵌入式开发的关键技术之一。
  • RingBuf-cpp11-源码

    2021-04-10 18:11:56
    RingBuf-cpp11
  • Algorithm-ringbuf.zip

    2019-09-17 11:56:58
    Algorithm-ringbuf.zip,无锁环形缓冲器(MPSC),算法是为计算机程序高效、彻底地完成任务而创建的一组详细的准则。
  • 环缓冲 Ringbuf 是 go 语言的 ringbuffer 的简单无锁​​实现。
  • 51环形缓冲区代码,能有效提高缓冲区操作,读写指针分离,互不干扰
  • * ringBuf, char * pSrc, int nByteSize); bool readRingBuf( char * ringBuf, char * pBuffer, int & nByteSize); private : bool isCanRead( char * ringBuf); // 判断是否可以再进行读操作 bool ...
  • 一个环形缓冲(ringbuf)的简单实现

    千次阅读 2014-01-16 20:49:28
    代码中有相关注释: ...#ifndef _RINGBUF_HEADER_ #define _RINGBUF_HEADER_ #ifdef _cplusplus extern "C"{ #endif /************* 1 === succeed 0 === failed *************/ typedef struct _ringbuf_
  • 环形缓冲区: ringbuf.c

    2018-01-02 12:29:00
    /*ringbuf .c*/ #include<stdio.h> #include<ctype.h> #define NMAX 8 int iput = 0; /* 环形缓冲区的当前放入位置 */ int iget = 0; /* 缓冲区的当前取出位置 */ int n = 0; /* 环形缓冲区中的元素总...
  • go实现Ringbuf

    2015-10-20 22:36:00
    return &Ringbuf{make([]byte, size), 0, 0} } func (r *Ringbuf) Write(b []byte) { for len(b) > 0 { start := (r.start + r.size) % len(r.buf) n := copy(r.buf[start:], b) b ...
  • ringBuf源码头文件

    2010-02-10 21:01:50
    头文件,嵌入式领域的ringBuf数据结构和算法的实现。是嵌入式开发的关键技术之一。
  • ringbuf的一个简单实现

    千次阅读 2013-04-23 15:31:00
    /* Opaque buffer element type. This would be defined by the application. */ typedef struct { void * buff; } ElemType; /* Circular buffer object */ typedef struct { int size; /* maximu
  • ringbuf_init (struct ringbuf *r, uint8_t *dataptr, uint16_t size) { r-> data = dataptr; r->mask = size - 1 ; r->put_ptr = 0 ; r->get_ptr = 0 ; } struct ringbuf ring_fifo; static ...
  • TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。粘包可能由发送方造成,也可能由接收方造成。TCP为提高传输效率,发送方往往要收集到足够多的数据...
  • 后来,我在开发ESP8266和基于cc2530的contiki系统时,都发现这些系统下面有一个RingBuf文件,说明这个RingBuf就是为了解决裸机单片机开发中队列的问题。下面我来分析一下ESP8266中的RingBuf代码。
  • BPF环形缓冲区

    2021-02-21 20:37:34
    BPF Ringbuf和BPF perfbuf 内存开销 活动订购 浪费工作和额外的数据复制 性能和适用性 给我看看代码! BPF perfbuf:bpf_perf_event_output() BPF ringbuf:bpf_ringbuf_output() BPF ringbuf:保留/...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 615
精华内容 246
关键字:

ringbuf