为什么我们保留互斥锁而不是每次都守卫前声明它
Why we keep mutex instead of declaring it before guard every time?
请考虑这种经典方法,我将其简化以突出确切的问题:
#include <iostream>
#include <mutex>
using namespace std;
class Test
{
public:
void modify()
{
std::lock_guard<std::mutex> guard(m_);
// modify data
}
private:
/// some private data
std::mutex m_;
};
这是使用std::mutex
来避免数据竞争的经典方法。
问题是为什么我们在课堂上多留std::mutex
?为什么我们不能每次都像这样在std::lock_guard
宣布之前宣布它?
void modify()
{
std::mutex m_;
std::lock_guard<std::mutex> guard(m_);
// modify data
}
假设两个线程并行调用modify
。因此,每个线程都有自己的新互斥锁。因此,guard
不起作用,因为每个防护装置都锁定了不同的互斥锁。您尝试保护的资源免受争用条件的影响将被公开。
误解来自mutex
是什么以及lock_guard
有什么好处。
是不同线程之间共享的对象,每个线程都可以锁定和释放互斥锁。这就是不同线程之间的同步的工作方式。因此,您也可以使用 m_.lock()
和 m_.unlock()
,但您必须非常小心,确保函数中的所有代码路径(包括异常退出(实际上都会解锁互斥锁。
为了避免缺少解锁的陷阱,lock_guard
是一个包装对象,它在创建包装对象时锁定互斥锁,并在销毁包装器对象时解锁互斥锁。由于包装器对象是具有自动存储持续时间的对象,因此您永远不会错过解锁 - 这就是原因。
互斥锁没有意义,因为它是本地的,而不是共享资源。本地lock_guard完全有意义,因为自动存储持续时间可防止丢失锁定/解锁。
希望对您有所帮助。
这一切都取决于您要防止并行执行的内容的上下文。
当多个线程尝试访问同一个互斥锁对象时,互斥锁将起作用。因此,当 2 个线程尝试访问并获取互斥对象的锁时,只有一个线程会成功。
现在在第二个示例中,如果两个线程调用modify()
,则每个线程都有自己的互斥锁实例,因此没有什么可以阻止它们并行运行该函数,就好像没有互斥锁一样。
所以回答你的问题:这取决于上下文。该设计的任务是确保所有不应并行执行的线程将在关键部分命中相同的互斥对象。
线程同步涉及检查是否有另一个线程执行关键部分。mutex
是保存状态的对象,供我们检查它是否被线程"锁定"。 另一方面,lock_guard
是一个包装器,它在初始化时lock
mutex
,并在销毁期间unlock
它。
意识到这一点后,应该更清楚为什么所有lock_guard
都需要访问的mutex
只有一个实例 - 他们需要检查是否清楚地针对同一对象进入关键部分。在问题的第二个代码段中,每个函数调用都会创建一个单独的mutex
,该只能在其本地上下文中看到和访问。
你需要类级别的互斥锁。否则,每个线程都有一个互斥锁,因此互斥锁不起作用。
如果出于某种原因您不希望将互斥锁存储在类属性中,则可以使用静态互斥锁,如下所示。
void modify()
{
static std::mutex myMutex;
std::lock_guard<std::mutex> guard(myMutex);
// modify data
}
请注意,这里所有类实例只有 1 个互斥锁。如果互斥锁存储在属性中,则每个类实例将有一个互斥锁。根据您的需求,您可能更喜欢一种解决方案或另一种解决方案。
- .cpp和.h文件中的模板专用化声明
- 未在作用域中声明unordered_map
- C++避免重复声明的语法是什么
- 如何确保C++函数在定义之前声明(如override关键字)
- 错误:未在此范围内声明'reverse'
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 为什么在定义函数之前先声明它
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- #ifdef和未声明的标识符
- 没有显式声明的int[]中的foreach
- 在基于范围的for循环中使用结构化绑定声明
- 在将变量声明为引用时,堆在释放后使用
- C++:无法访问声明的受保护成员
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- 在函数内部的声明中初始化数组,并在外部使用它
- Visual Studio中的函数声明和函数定义问题
- c++类声明时,相同的例程,不同的成员变量类型
- 为什么我们保留互斥锁而不是每次都守卫前声明它