簡體   English   中英

動態循環緩沖隊列

[英]Dynamic circular buffer queue

我正在嘗試實現一個線程安全的 mcmp-queue,我正在使用一個可調整大小的循環緩沖區來執行此操作,但是我遇到了錯誤。 目前我只是通過在一個線程上寫入隊列並在另一個線程上讀取它來測試以下類; 但我得到了意想不到的輸出。 我懷疑我的調整大小被竊聽了,但我目前正在摸索我做錯了什么,任何幫助將不勝感激。

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;
    }
};
if (_tail < _head)
{
    auto to_copy = (_data + _head) - (_data + _capacity);

這樣對嗎? 正如所寫的那樣,看起來數據被抵消了,留下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;

這里不應該也重新調整尾部索引嗎? 假設tail==10,head==3,copy head變為0后,tail仍為10。(我還沒有分析過if條件是否成立)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM