与普通互斥锁相比,唯一锁如何工作?
How do unique locks work compared to normal mutex locks?
我遇到了 book 提供的代码示例。顺便说一句,这本书的评论很差。后悔买了
std::mutex m_mutex;
mutable std::unique_lock<std::mutex> m_finishedQueryLock{ m_mutex, std::defer_lock };
bool m_playerQuit{ false };
void SetPlayerQuit()
{
m_finishedQueryLock.lock();
m_playerQuit = true;
m_finishedQueryLock.unlock();
}
我不满意本书对它的工作原理以及我为什么要使用它的解释。我已经对互斥锁的工作原理及其实现有所了解,但我很难理解上面代码的第二行。为什么它里面有一个可变关键字?
我对 C++ 编程完全陌生。所以基本水平的解释会对我有很大帮助。
unique_lock
是一个 RAII 系统。创建时,以 mutex
作为参数,它将锁定互斥锁,并在离开作用域时销毁它,从而解锁互斥锁。当你需要提前解锁时,你可以像你的例子一样调用unlock()
函数。
像在您的示例中那样使用 unique_lock
并不会比直接使用互斥锁产生更多的价值。
这个例子看起来很愚蠢。
第二行声明了一个非静态数据成员,并且
- 成员是
mutable
(原因如下);
- 该成员是
std::unique_lock<std::mutex>
类型的对象,它是 locking/unlocking 关联互斥对象的辅助类型;
- 成员在创建 class 的实例时初始化,方法是调用其构造函数并将
m_mutex
和特殊标记 std::defer_lock
作为参数传递。
但这样做是愚蠢的,如果这本书有这样的例子,我不会感到惊讶。
unique_lock
的要点是锁定关联的互斥锁,然后在它超出范围时自动解锁。像这样创建一个 unique_lock
成员是愚蠢的,因为它不会在函数末尾超出范围,所以代码绝对没有优势:
mutable std::mutex m_mutex;
bool m_playerQuit{ false };
void SetPlayerQuit()
{
m_mutex.lock();
m_playerQuit = true;
m_mutex.unlock();
}
但是这个手动解锁具有 unique_lock
旨在解决的所有问题,因此它应该使用范围锁(unique_lock
或 lock_guard
)但仅限于功能范围,不作为成员:
mutable std::mutex m_mutex;
bool m_playerQuit{ false };
void SetPlayerQuit()
{
std::lock_guard<std::mutex> lock(m_mutex);
m_playerQuit = true;
} // m_mutex is automatically unlocked by the ~lock_guard destructor
mutable
关键字是必需的,以便您可以在 const
成员函数中锁定互斥锁。锁定和解锁互斥量是一种修改互斥量的非常量操作,如果它不是可变的,则在 const
成员中是不允许的。
所有答案都很好地解释了为什么这个例子不好。当您想使用 std::unique_lock
而不是 std::lock_guard
.
时,我会回答
当线程正在等待某事时,可以使用 std::condition_variable
。条件变量使用延迟锁定,因此使用 unique_lock
,它允许延迟锁定。我认为您不需要像示例中那样明确说明需要延迟锁定。
要掌握这些概念,首先需要了解什么是RAII。那就看看this reference. An example of the condition variables can be found here.
我遇到了 book 提供的代码示例。顺便说一句,这本书的评论很差。后悔买了
std::mutex m_mutex;
mutable std::unique_lock<std::mutex> m_finishedQueryLock{ m_mutex, std::defer_lock };
bool m_playerQuit{ false };
void SetPlayerQuit()
{
m_finishedQueryLock.lock();
m_playerQuit = true;
m_finishedQueryLock.unlock();
}
我不满意本书对它的工作原理以及我为什么要使用它的解释。我已经对互斥锁的工作原理及其实现有所了解,但我很难理解上面代码的第二行。为什么它里面有一个可变关键字?
我对 C++ 编程完全陌生。所以基本水平的解释会对我有很大帮助。
unique_lock
是一个 RAII 系统。创建时,以 mutex
作为参数,它将锁定互斥锁,并在离开作用域时销毁它,从而解锁互斥锁。当你需要提前解锁时,你可以像你的例子一样调用unlock()
函数。
像在您的示例中那样使用 unique_lock
并不会比直接使用互斥锁产生更多的价值。
这个例子看起来很愚蠢。
第二行声明了一个非静态数据成员,并且
- 成员是
mutable
(原因如下); - 该成员是
std::unique_lock<std::mutex>
类型的对象,它是 locking/unlocking 关联互斥对象的辅助类型; - 成员在创建 class 的实例时初始化,方法是调用其构造函数并将
m_mutex
和特殊标记std::defer_lock
作为参数传递。
但这样做是愚蠢的,如果这本书有这样的例子,我不会感到惊讶。
unique_lock
的要点是锁定关联的互斥锁,然后在它超出范围时自动解锁。像这样创建一个 unique_lock
成员是愚蠢的,因为它不会在函数末尾超出范围,所以代码绝对没有优势:
mutable std::mutex m_mutex;
bool m_playerQuit{ false };
void SetPlayerQuit()
{
m_mutex.lock();
m_playerQuit = true;
m_mutex.unlock();
}
但是这个手动解锁具有 unique_lock
旨在解决的所有问题,因此它应该使用范围锁(unique_lock
或 lock_guard
)但仅限于功能范围,不作为成员:
mutable std::mutex m_mutex;
bool m_playerQuit{ false };
void SetPlayerQuit()
{
std::lock_guard<std::mutex> lock(m_mutex);
m_playerQuit = true;
} // m_mutex is automatically unlocked by the ~lock_guard destructor
mutable
关键字是必需的,以便您可以在 const
成员函数中锁定互斥锁。锁定和解锁互斥量是一种修改互斥量的非常量操作,如果它不是可变的,则在 const
成员中是不允许的。
所有答案都很好地解释了为什么这个例子不好。当您想使用 std::unique_lock
而不是 std::lock_guard
.
当线程正在等待某事时,可以使用 std::condition_variable
。条件变量使用延迟锁定,因此使用 unique_lock
,它允许延迟锁定。我认为您不需要像示例中那样明确说明需要延迟锁定。
要掌握这些概念,首先需要了解什么是RAII。那就看看this reference. An example of the condition variables can be found here.