condition_variable、引用和线程:谁拥有锁?

condition_variable, references and threads: Who Owns The Lock?

本文关键字:拥有 线程 variable 引用 condition      更新时间:2023-10-16

>假设我有一个保存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?

代码中有两个主要错误:

  1. unique_lock不应是成员变量。必须在堆栈上创建它,以便在离开作用域时(在正常返回或异常时(自动为您释放锁。
  2. 只有在检查队列确实为空后,才必须调用cv.waitstd::condition_variable是一种无状态通信机制,如果在没有服务员时发出信号,则信号丢失。还有虚假的唤醒。您可能希望使用cv.wait([this] { return !q_.empty(); });来正确处理条件变量的等待。

例如:

using namespace std;
template <typename T>
class ThreadQueue
{
queue<T> q_;
mutex mtx;
condition_variable cv;
public:
void enqueue (const T&);
T dequeue ();
};
template <typename T>
void ThreadQueue<T>::enqueue (const T& t)
{
{
lock_guard<mutex> lck(mtx);
q_.push(t);
}
cv.notify_one(); // Optimization: release the lock before signalling.
}
template <typename T>
T ThreadQueue<T>::dequeue ()
{
unique_lock<mutex> lck(mtx);
cv.wait(lck, [this] { return !q_.empty(); });
T t = q_.front();
q_.pop();
return t;
}

谁拥有锁?

锁定互斥锁的线程拥有锁,或进入关键部分std::lock_guardstd::unique_lock在这里都锁定构造函数中的互斥锁并在析构函数中解锁(在正常范围退出或异常时(。