【发布时间】: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;
}
我对几个部分很困惑:
为什么 front() 函数返回 T&(对某个类型 T 的引用)?
为什么 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