【发布时间】:2020-05-26 02:26:58
【问题描述】:
假设我有一个持有std::queue 的类ThreadQueue,并且我将每个std::ref 的一个实例传递给一个线程。进一步假设,线程 1(主线程)创建并持有 ThreadQueue 对象并将消息倒入其中,第二个线程的任务是在收到这些消息时将它们放在某个地方,例如,将它们写入日志文件。
类看起来像:
#include <queue>
#include <mutex>
#include <condition_variable>
using namespace std;
template <typename T>
class ThreadQueue
{
queue<T> q_;
mutex mtx;
unique_lock<mutex> lck;
condition_variable cv;
public:
ThreadQueue() { lck = unique_lock<mutex>(mtx); }
~ThreadQueue() { if (lck.owns_lock()) lck.unlock(); }
void enqueue (const T&);
T dequeue ();
};
template <typename T>
void ThreadQueue<T>::enqueue (const T& t)
{
lck.lock();
q_.push(t);
lck.unlock();
cv.notify_one();
}
template <typename T>
T ThreadQueue<T>::dequeue ()
{
cv.wait(lck);
lck.lock();
T t = q_.front(); // let's assume that's a copy assignment, because
q_.pop(); // pop() calls the descructor.
lck.unlock();
return t;
}
然后主要的曲调是:
ThreadQueue<std::pair<int, std::string>> logs;
// and maybe something like:
std::thread logger(std::ref(logs));
关键行是cv.wait(lck); 文档明确指出lck 必须是一个unique_lock 对象,其互斥对象当前已被该线程锁定。
现在的问题是:谁真正锁定了互斥锁,谁拥有锁,线程 1 还是线程 2?
【问题讨论】:
-
你已经为任何使用这个类的人创建了一个解除锁。关键是创建一个
std::unique_lock作为线程安全函数的局部变量,并将其作为对`std::consition_variable 的引用传递。没有必要保留一个唯一的锁作为成员变量。
标签: c++ c++11 concurrency condition-variable