【问题标题】:Dynamic circular buffer queue动态循环缓冲队列
【发布时间】:2021-10-03 19:46:04
【问题描述】:

我正在尝试实现一个线程安全的 mcmp 队列,我正在使用一个可调整大小的循环缓冲区来执行此操作,但我遇到了错误。目前我只是通过在一个线程上写入队列并在另一个线程上读取它来测试以下类;但我得到了意想不到的输出。我怀疑我的大小调整有问题,但我目前正在摸索我做错了什么,任何帮助将不胜感激。

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;
    }
};

解决了我最初遇到的问题的修订实现:

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;
    }
};

【问题讨论】:

  • 请提供minimal reproducible example。出了什么问题?你试过调试吗?
  • MRE 会很好,而且:您是否尝试过用 std::vector 替换手动分配的数组?假设它工作正常(某种“已被证明在使用中”的前提条件),你会得到一个答案,它是否实际上是在调整导致问题的例程。
  • 您还应该在构造函数或声明它们的位置初始化所有数据成员。否则它们不能保证为 0——它们只是未初始化。阅读它们是未定义的行为。

标签: c++ concurrency c++20


【解决方案1】:
if (_tail < _head)
{
    auto to_copy = (_data + _head) - (_data + _capacity);

这是正确的吗?正如所写,看起来数据被取消了,留下head - capacity作为你要复制的数量,这可能会变成负数......

【讨论】:

    【解决方案2】:
                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;
    

    这里不应该也重新调整尾索引吗? 假设tail==10,head==3,拷贝head变为0后,tail保持为10。 (而且我还没有分析 if 条件被满足)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-08
      • 1970-01-01
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-08
      相关资源
      最近更新 更多