std::lock_guard
是 C++ 标准库中的一个类模板,用于自动管理互斥锁(std::mutex
或其派生类)的锁定和解锁。它的主要目的是提供一种简便且安全的方式来保护临界区(critical sections)免受数据竞争(data race)的影响。
主要特性
-
自动锁定和解锁:当
std::lock_guard
对象被创建时,它会自动锁定提供的互斥锁。当该对象离开其作用域(即被销毁)时,它会自动解锁互斥锁。这种自动管理确保了即使在发生异常的情况下,互斥锁也能被正确解锁。 -
简单易用:
std::lock_guard
的使用非常简单,只需要在需要保护的代码块之前创建它即可。无需显式调用锁定和解锁函数。 -
非递归:
std::lock_guard
不支持递归锁定,即不能多次锁定同一个互斥锁。如果尝试这样做,会导致未定义的行为。
使用方法
使用 std::lock_guard
的基本步骤如下:
-
包含头文件:
首先,需要包含<mutex>
头文件以使用std::lock_guard
和相关的互斥锁类型。#include <mutex>
-
定义互斥锁:
在需要保护的代码段之前或附近定义一个std::mutex
对象。std::mutex mtx;
-
使用 std::lock_guard:
在需要保护的代码块之前创建std::lock_guard
对象,并将互斥锁作为参数传递给它。{
std::lock_guard<std::mutex> guard(mtx);
// 临界区代码,此时 mtx 被锁定
// ...
} // 当 guard 对象离开作用域时,mtx 会被自动解锁
在这个例子中,当 std::lock_guard<std::mutex> guard(mtx);
被执行时,mtx
会被锁定。然后,在 guard
对象的作用域内,任何尝试锁定 mtx
的其他线程都会被阻塞,直到 guard
对象被销毁(即离开其作用域),此时 mtx
会自动解锁。
注意事项
- 不要手动解锁:使用
std::lock_guard
时,不需要(也不应该)手动调用解锁函数。std::lock_guard
会在其析构函数中自动解锁互斥锁。 - 避免递归锁定:如前所述,
std::lock_guard
不支持递归锁定。如果尝试多次锁定同一个互斥锁,会导致未定义的行为。 - 避免在循环中使用:由于
std::lock_guard
在其析构函数中解锁互斥锁,因此如果在循环中创建和销毁它,可能会导致性能下降。在这种情况下,考虑使用std::unique_lock
,它允许在循环中保持锁定状态。 - 异常安全性:
std::lock_guard
提供了异常安全性,即使在临界区代码中抛出异常,互斥锁也能被正确解锁。这是因为它在析构函数中解锁互斥锁,而析构函数在异常处理期间也会被调用。