condition_variable、引用和线程:谁拥有锁?
condition_variable, references and threads: Who Owns The Lock?
>假设我有一个保存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?
代码中有两个主要错误:
unique_lock
不应是成员变量。必须在堆栈上创建它,以便在离开作用域时(在正常返回或异常时(自动为您释放锁。- 只有在检查队列确实为空后,才必须调用
cv.wait
。std::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_guard
和std::unique_lock
在这里都锁定构造函数中的互斥锁并在析构函数中解锁(在正常范围退出或异常时(。
相关文章:
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 如何将元素添加到数组的线程安全函数?
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- condition_variable、引用和线程:谁拥有锁?
- 让线程拥有它C++运行的函子
- 在另一个 QThread 上运行成员方法时,无法将事件发送到其他线程拥有的对象
- QT:QT无法将事件发送到另一个线程拥有的对象 - 原因
- 为什么我的程序在拥有线程的情况下生成LdrpLoaderLock死锁
- 如何在英特尔TBB中拥有长时间等待的线程
- C++线程:可以lock_guard拥有一个unique_lock所拥有的互斥对象
- C++-初始化由不同线程拥有的对象的两个副本
- 在应用程序中拥有大量线程会适得其反
- 在窗口关闭(或其拥有线程消失)时收到通知
- 如何打印linux上进程拥有的所有线程的线程id
- 我如何避免许多线程锁在互斥锁(拥有)的线程睡眠