c_cpp 环形缓冲区

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 环形缓冲区相关的知识,希望对你有一定的参考价值。

/*
 *  Simple lockfree implementation of single producer/consumer circular FIFO buffer
 */

#ifndef RINGBUFFER_H
#define RINGBUFFER_H

#include <algorithm>
#include <memory.h>
#include <atomic>

namespace Utility
{

template<typename T> class ringbuffer {
public:
    
    //do not allow default constructor
    ringbuffer() = delete;
    
    /**
     * create a ringbuffer with space for up to size elements.
     */
    explicit ringbuffer(size_t size)
    : size(size + 1)
    , m_begin(0)
    , m_end(0) {
        buffer = new T[size];
    }
    
    /**
     * copy constructor
     */
    ringbuffer(const ringbuffer<T> & rb) {
        this(rb.size);
        m_begin = rb.m_begin;
        m_end = rb.m_end;
        memcpy(buffer, rb.buffer, sizeof(T) * size);
    }
    
    ~ringbuffer() {
        delete[] buffer;
    }
    
    size_t write(const T * data, size_t n) noexcept
    {
        if (getFree() < n || n == 0) {
            return 0;
        }
        
        auto end = m_end.load(std::memory_order_relaxed);
        const size_t first_chunk = std::min(n, size - end);
        memcpy(buffer + end, data, first_chunk * sizeof(T));
        end = (end + first_chunk) % size;
        m_end.store(end, std::memory_order_release);
        
        if (first_chunk < n) {
            const size_t second_chunk = n - first_chunk;
            memcpy(buffer + end, data + first_chunk, second_chunk * sizeof(T));
            end = (end + second_chunk) % size;
            m_end.store(end, std::memory_order_release);
        }
        
        return n;
    }
    
    size_t read(T * dest, size_t n) noexcept {
        if (n > getOccupied() || n == 0) {
            return 0;
        }
        
        auto begin = m_begin.load(std::memory_order_relaxed);
        const size_t first_chunk = std::min(n, size - begin);
        memcpy(dest, buffer + begin, first_chunk * sizeof(T));
        begin = (begin + first_chunk) % size;
        m_begin.store(begin, std::memory_order_release);
        
        if (first_chunk < n) {
            const size_t second_chunk = n - first_chunk;
            memcpy(dest + first_chunk, buffer + begin, second_chunk * sizeof(T));
            begin = (begin + second_chunk) % size;
            m_begin.store(begin, std::memory_order_release);
        }
        
        return n;
    }
    
    size_t capacity() const noexcept {
        return size - 1;
    }
    
    size_t getOccupied() const noexcept {
        auto end = m_end.load();
        auto begin = m_begin.load();
        
        if (end == begin) {
            return 0;
        } else if (end > begin) {
            return end - begin;
        } else {
            return size + end - begin;
        }
    }
    
    size_t getFree() const {
        assert(size - getOccupied() - 1 >= 0);
        return size - getOccupied() - 1;
    }
private:
    T * buffer;
    const size_t size;
    std::atomic<size_t> m_begin;
    std::atomic<size_t> m_end;
};
    
}

#endif // RINGBUFFER_H

以上是关于c_cpp 环形缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

怎么计算环形缓冲区长度

环形缓冲区大小和反写阈值

微控制器的环形缓冲区

环形缓冲区

关于环形缓冲区

数据结构之环形缓冲器