【问题标题】:C++ Thread-safe Queue Implementation input and return typesC++ 线程安全队列实现输入和返回类型
【发布时间】:2020-01-10 05:46:49
【问题描述】:

我从这篇文章中找到了以下代码:Why is std::queue not thread-safe?

#pragma once

#include <queue>
#include <mutex>
#include <condition_variable>

    template <typename T>
    class SharedQueue
    {
    public:
        SharedQueue();
        ~SharedQueue();

        T& front();
        void pop_front();

        void push_back(const T& item);
        void push_back(T&& item);

        int size();
        bool empty();

    private:
        std::deque<T> queue_;
        std::mutex mutex_;
        std::condition_variable cond_;
    }; 

    template <typename T>
    SharedQueue<T>::SharedQueue(){}

    template <typename T>
    SharedQueue<T>::~SharedQueue(){}

    template <typename T>
    T& SharedQueue<T>::front()
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        while (queue_.empty())
        {
            cond_.wait(mlock);
        }
        return queue_.front();
    }

    template <typename T>
    void SharedQueue<T>::pop_front()
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        while (queue_.empty())
        {
            cond_.wait(mlock);
        }
        queue_.pop_front();
    }     

    template <typename T>
    void SharedQueue<T>::push_back(const T& item)
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        queue_.push_back(item);
        mlock.unlock();     // unlock before notificiation to minimize mutex con
        cond_.notify_one(); // notify one waiting thread

    }

    template <typename T>
    void SharedQueue<T>::push_back(T&& item)
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        queue_.push_back(std::move(item));
        mlock.unlock();     // unlock before notificiation to minimize mutex con
        cond_.notify_one(); // notify one waiting thread

    }

    template <typename T>
    int SharedQueue<T>::size()
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        int size = queue_.size();
        mlock.unlock();
        return size;
    }

我对几个部分很困惑:

  1. 为什么 front() 函数返回 T&(对某个类型 T 的引用)?

  2. 为什么 push_back 将 const T& 和 T&& in 作为类型?

这里有必要吗?

谢谢!

更新:

template <typename T>
T SharedQueue<T>::pop_front()
{
    std::unique_lock<std::mutex> mlock(mutex_);
    while (queue_.empty())
    {
        cond_.wait(mlock);
    }
    T retFront = queue_.front();
    queue_.pop_front();
    return retFront;
}

【问题讨论】:

  • 我想我只是想了解他们为什么在那里。例如,front() 函数返回对 T 的引用。这是否意味着它可以用作左值?那么,front() 函数本质上是设置队列的第一个值?
  • @cmed123 因为那会制作另一个对象副本来构造函数参数。不过,您不想复制,只想将对象传递给实际的queue_push_back。如果您将来自 cmets 的问题添加到问题帖子中,我认为答案会更加集中和清晰。
  • @cmed123 这与保存在队列中的引用无关。队列总是保存一个副本。但是如果你将按值传递给push_back,那么在从参数复制/移动构造队列元素之前,push_back 的参数将会有另一个复制操作。这个副本总是会毫无意义地浪费资源。
  • @cmed123 不,它只是一个右值引用。它不是转发引用,因为T 不是函数的模板参数(它是类的模板参数)。 (这也是我和 Evg 上面的误会。)
  • @deleted 评论:是的,当另一个线程可能同时调用 pop_front 时,front 是不安全的。代码中的接口复制了std::deque的接口,这在多线程代码中确实可能有问题。 @cmed123:如果您希望能够安全地使用front 而另一个线程可能正在调用pop_front,那么您需要让它按值返回,而不是引用。这限制了它的可用性,但在这种情况下是安全的。

标签: c++ multithreading queue


【解决方案1】:

使用 void push_back(T&& item) 可以显着减少 CPU/内存使用(如果您的参数可用于“移动”)。 “能”不代表“会”。

为什么支持两种形式的 push_back?恕我直言,“按设计”(这是开发人员设计)。在某些情况下,您可以使用带有 forward 的单一表单。

【讨论】:

    猜你喜欢
    • 2017-06-14
    • 2012-05-30
    • 1970-01-01
    • 2012-11-05
    • 1970-01-01
    • 2015-02-16
    • 2013-02-23
    • 1970-01-01
    • 2010-10-22
    相关资源
    最近更新 更多