简体   繁体   English

动态循环缓冲队列

[英]Dynamic circular buffer queue

I'm trying to implement a thread-safe mcmp-queue, I'm doing this with a resizable circular buffer, but I'm running into bugs.我正在尝试实现一个线程安全的 mcmp-queue,我正在使用一个可调整大小的循环缓冲区来执行此操作,但是我遇到了错误。 Currently I'm just testing the following class by writing to the queue on one thread, and reading it on another;目前我只是通过在一个线程上写入队列并在另一个线程上读取它来测试以下类; but I get unexpected outputs.但我得到了意想不到的输出。 I suspect my resizing is bugged, but I'm currently scratching my head as to what I'm doing wrong, any help would be appreciated.我怀疑我的调整大小被窃听了,但我目前正在摸索我做错了什么,任何帮助将不胜感激。

template <typename T>
class queue
{
public:
    queue() = default;
    queue(std::size_t capacity) : _data(new T[capacity]), _capacity(capacity){};

    void enqueue(T const& item)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_full())
            _resize();

        _push(item);
    }

    std::optional<T> dequeue()
    {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_empty())
            return std::nullopt;

        auto front = _front();
        _pop();
        return std::move(front);
    }

private:
    T *_data;
    std::size_t _capacity;
    std::size_t _head;
    std::size_t _tail;
    std::mutex _mutex;

    std::size_t _size() const
    {
        if(_tail < _head)
            return _capacity - _head + _tail;

        return _tail - _head;
    }

    bool _empty()
    {
        return _size() == 0;
    }

    void _push(T const& value)
    {
        _data[_tail] = value;
        _tail = (_tail + 1) % _capacity;
    }
    
    bool _full()
    {
        return _size() == _capacity;
    }

    void _resize()
    {
        auto new_capacity = (_capacity == 0) ? 2 : _capacity * 2;
        T* new_data = new T[new_capacity];

        if(_data)
        {
            // std::copy(_data, _data + _capacity, new_data);
            if (_tail < _head)
            {
                auto to_copy = (_data + _head) - (_data + _capacity);
                std::copy(_data + _head, _data + _capacity, new_data);
                std::copy(_data, _data + _head, new_data + to_copy);
            }
            else
            {
                //std::copy(_data + _head, _data + _capacity, new_data);
                std::copy(_data + _head, _data + _tail, new_data);
            }
            delete[] _data;
        }
        _data = new_data;
        _capacity = new_capacity;
        _head = 0;
    }

    T& _front()
    {
        return _data[_head];
    }

    void _pop()
    {
        _head = (_head + 1) % _capacity;
    }
};

Revised implementation that solves the problem I was originally having:修改后的实现解决了我最初遇到的问题:

template <typename T>
class queue
{
public:

    void enqueue(T const& item)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        if(_full())
            _resize();

        _data[_tail] = item;
        _tail = (_tail + 1) % _capacity;
    }

    std::optional<T> dequeue()
    {
        std::lock_guard<std::mutex> lock(_mutex);
        if(_empty())
            return std::nullopt;
        
        T item = std::move(_data[_head]);
        _head = (_head + 1) % _capacity;
        return item;
    }

private:
    T *_data;
    std::size_t _capacity;
    std::size_t _head;
    std::size_t _tail;
    std::mutex _mutex;

    bool _full()
    {
        return (_size() == _capacity);
    }

    std::size_t _size()
    {
        return (_head - _tail) & (_capacity - 1);
    }

    bool _empty()
    {
        return (_size() == 0);
    }

    void _resize()
    {
        auto new_capacity = (_capacity == 0) ? 2 : _capacity * 2;
        auto new_array = new T[new_capacity];

        auto size = _size();

        if (size > 0)
        {
            if(_head < _tail)
            {
                std::copy(_data + _head, _data + size, new_array);
            }
            else
            {
                std::copy(_data + _head, _data + (size - _head), new_array);
                std::copy(_data, _data + _tail, new_array + (size - _head));
            }
        }

        _capacity = new_capacity;
        _data = new_array;
        _head = 0;
        _tail = (size == _capacity) ? 0 : size;
    }
};
if (_tail < _head)
{
    auto to_copy = (_data + _head) - (_data + _capacity);

Is this correct?这样对吗? As written, looks like data cancels out, leaving head - capacity as your amount to copy, which can go negative...正如所写的那样,看起来数据被抵消了,留下head - capacity作为您要复制的数量,这可能会变成负数......

            else
            {
                //std::copy(_data + _head, _data + _capacity, new_data);
                std::copy(_data + _head, _data + _tail, new_data);
            }
            delete[] _data;
        }
        _data = new_data;
        _capacity = new_capacity;
        _head = 0;

shouldn't tail index be also re-adjusted here?这里不应该也重新调整尾部索引吗? Assume tail==10, head==3, after copy head becomes 0, tail remains 10. (and I haven't analyzed the if condition being met).假设tail==10,head==3,copy head变为0后,tail仍为10。(我还没有分析过if条件是否成立)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM