是否可以实现由数组组成的线程安全循环缓冲区?

Is it possible to implement a thread safe circular bufffer that consists of arrays?

我正在尝试实现一个循环缓冲区,该缓冲区利用互斥锁来保证线程安全。我一直在使用以下代码:

#include <cstdio>

#include <memory>
#include <mutex>

template <class T>
class circular_buffer {
public:
    explicit circular_buffer(size_t size) :
        buf_(std::unique_ptr<T[]>(new T[size])),
        max_size_(size)
    {

    }

    void put(T item)
    {
        std::lock_guard<std::mutex> lock(mutex_);

        buf_[head_] = item;

        if (full_)
        {
            tail_ = (tail_ + 1) % max_size_;
        }

        head_ = (head_ + 1) % max_size_;

        full_ = head_ == tail_;
    }

    T get()
    {
        std::lock_guard<std::mutex> lock(mutex_);

        if (empty())
        {
            return T();
        }

        //Read data and advance the tail (we now have a free space)
        auto val = buf_[tail_];
        full_ = false;
        tail_ = (tail_ + 1) % max_size_;

        return val;
    }

    void reset()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        head_ = tail_;
        full_ = false;
    }

    bool empty() const
    {
        //if head and tail are equal, we are empty
        return (!full_ && (head_ == tail_));
    }

    bool full() const
    {
        //If tail is ahead the head by 1, we are full
        return full_;
    }

    size_t capacity() const
    {
        return max_size_;
    }

    size_t size() const
    {
        size_t size = max_size_;

        if (!full_)
        {
            if (head_ >= tail_)
            {
                size = head_ - tail_;
            }
            else
            {
                size = max_size_ + head_ - tail_;
            }
        }

        return size;
    }

private:
    std::mutex mutex_;
    std::unique_ptr<T[]> buf_;
    size_t head_ = 0;
    size_t tail_ = 0;
    const size_t max_size_;
    bool full_ = 0;
};

这段代码的问题是我似乎无法让它与浮点数组一起工作。我收到函数 returns 数组错误(来自 get 函数)。我不完全确定如何解决这个问题(尝试传入一个数组并使用 get() 函数指向该数组,但这也不起作用)。抱歉,如果这个问题有点抽象,老实说,我对这个问题完全不知所措(作为开发人员的第一份工作,实际上是我工作的 6 天,他们让我制作了一个非常复杂的雷达测绘应用程序)。如果您需要任何说明,请告诉我。

编辑:谢谢大家! Michael 的回答有效,感谢您的建议。老实说,我现在感觉自己快被淹没了,所以所有的提示都非常有用!

首先,请注意,如果有人使用此 class 模板实例的 size()empty()full() 方法,而其他人正在同时使用 get()put()reset(),您最终会出现未定义的行为。 size()empty() 也必须锁定互斥量,因为它们读取可能被修改的对象(full_head_tail_)的值同时。除此之外,在我看来 put() 总是写一些东西,即使队列已满。这可能不是人们通常想要的。

根据您的描述,我认为您询问的问题与尝试创建有关,例如 circular_buffer<float[4]>。想想如果用类型 float[4] 代替 T:

get() 方法会变成什么
float get()[4] { … }

你最终得到一个函数 returning 数组。函数不允许 return 数组 [dcl.fct]/11.* That's why you end up with a compiler error as soon as you'd call the get() method on such a circular_buffer. Use, e.g., std::array 而是:circular_buffer<std::array<float, 4>>.

*) 我认为这很可能是出于历史原因。数组类型被设计为在传递给 C 中的函数时的行为方式使得数组最终将有效地通过引用传递;函数通过引用 return 数组没有好的方法,并且通过值 returning 将与它们的传入方式不一致。因此,最好只是禁止数组是 return 完全没有……