完整代码

template<typename T>
class BlockingQueue {
    const size_t capacity_;
    std::queue<T> queue_;
    std::mutex mutex_;
    std::condition_variable cvConsumer;
    std::condition_variable cvProducer;

public:
    BlockingQueue() : BlockingQueue(std::numeric_limits<size_t>::max()) {}

    explicit BlockingQueue(size_t maxCapacity)
            : capacity_(maxCapacity) {
        assert(maxCapacity > 0);
    }

    [[nodiscard]]
    T front() {
        std::unique_lock<std::mutex> lock(mutex_);
        cvConsumer.wait(lock, [this] {
            return !queue_.empty();
        });
        return queue_.front();
    }

    [[nodiscard]]
    T back() {
        std::unique_lock<std::mutex> lock(mutex_);
        cvConsumer.wait(lock, [this] {
            return !queue_.empty();
        });
        return queue_.back();
    }

    void push(const T &e) {
        std::unique_lock<std::mutex> lock(mutex_);
        cvProducer.wait(lock, [this] {
            return queue_.size() < capacity_;
        });
        queue_.emplace(e);
        cvConsumer.notify_one();
    }

    void push(T &&e) {
        std::unique_lock<std::mutex> lock(mutex_);
        cvProducer.wait(lock, [this] {
            return queue_.size() < capacity_;
        });
        queue_.emplace(std::forward<T>(e));
        cvConsumer.notify_one();
    }

    T pop() {
        std::unique_lock<std::mutex> lock(mutex_);
        cvConsumer.wait(lock, [this] {
            return !queue_.empty();
        });
        T value = std::move(queue_.front());
        queue_.pop();
        cvProducer.notify_one();
        return value;
    }

    [[nodiscard]]
    bool empty() {
        std::lock_guard<std::mutex> lock(mutex_);
        return queue_.empty();
    }

    [[nodiscard]]
    size_t size() {
        std::lock_guard<std::mutex> lock(mutex_);
        return queue_.size();
    }
};

为什么使用emplace而不是push

使用emplace将直接在容器内构造,避免了临时对象和拷贝。

为什么需要重载两个push函数

当实参为左值时,使用void push(const T &e) 传递一个常量左值引用可以避免不必要的拷贝,而当实参为右值时,使用void push(T &&e)传递右值引用,这可以利用移动语义避免拷贝,另外还使用了std::forward进行完美转发,使emplace也能利用移动语义避免拷贝。

其他

// 存在虚假唤醒
cv.wait(lock);
// 使用带谓词判断的重载可以避免虚假唤醒
cv.wait(lock, [] -> bool {
    return expr;
});

文章作者: Liccsu
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Liccsu's blog
笔记 C++
喜欢就支持一下吧
打赏
微信 微信