#include <mutex> 实现严格基于作用域的互斥体所有权包装器
template< class Mutex > class lock_guard;
类 lock_guard
是互斥封装器,为在作用域块期间占有互斥提供便利 RAII 风格机制。
创建 lock_guard
对象时,它试图接收给定互斥的所有权。控制离开创建 lock_guard
对象的作用域时,销毁 lock_guard
并释放互斥。
lock_guard
类不可复制。
模板形参
Mutex | - | 要锁定的互斥。类型必须满足基本可锁定 (BasicLockable) 要求 |
构造函数
explicit lock_guard( mutex_type& m ); (1) (C++11 起)
lock_guard( mutex_type& m, std::adopt_lock_t t ); (2) (C++11 起)
lock_guard( const lock_guard& ) = delete; (3) (C++11 起)
获得给定互斥 m
的所有权。
1) 等效地调用 m.lock() 。若 m
不是递归互斥,且当前线程已占有 m
则行为未定义。
2) 获得互斥 m 的所有权而不试图锁定它。若当前线程不占有 m
则行为未定义。
3) 复制构造函数被删除。
若在 m
先于 lock_guard
对象被销毁,则行为未定义。
参数
m | - | 要获得所有权的共享互斥 |
t | - | 用于选择构造函数非锁定版本的标签参数 |
异常
1) 抛任何 m.lock() 所抛的异常
2) 不抛出
析构函数
~lock_guard(); (C++11 起)
释放所占有互斥的所有权。
等效地调用 m.unlock() ,其中 m
是传递个 lock_guard
的构造函数的互斥。
调用示例
#include <thread>
#include <mutex>
#include <iostream>
int g_i = 0;
std::mutex g_i_mutex; // 保护 g_i
void safe_increment()
{
std::lock_guard<std::mutex> lock(g_i_mutex);
++g_i;
std::cout << std::this_thread::get_id() << ": " << g_i << '\n';
// g_i_mutex 在锁离开作用域时自动释放
}
int main()
{
std::cout << "main: " << g_i << '\n';
std::thread t1(safe_increment);
std::thread t2(safe_increment);
t1.join();
t2.join();
std::cout << "main: " << g_i << '\n';
}
可能得输出
用于指定锁定策略的标签类型
struct defer_lock_t { };
struct try_to_lock_t { };
struct adopt_lock_t { }; (C++11 起)(C++17 前)
std::defer_lock_t
、 std::try_to_lock_t
和 std::adopt_lock_t
是用于为 std::lock_guard 、 std::scoped_lock 、 std::unique_lock 和 std::shared_lock 指定锁定策略的空结构体标签类型。
类型 | 效果 |
defer_lock_t | 不获得互斥的所有权 |
try_to_lock_t | 尝试获得互斥的所有权而不阻塞 |
adopt_lock_t | 假设调用方线程已拥有互斥的所有权 |
用于指定锁定策略的标签常量
constexpr std::defer_lock_t defer_lock {}; (C++11 起) (C++17 前)
constexpr std::try_to_lock_t try_to_lock {}; (C++11 起) (C++17 前)
constexpr std::adopt_lock_t adopt_lock {}; (C++11 起) (C++17 前)
std::defer_lock
、 std::try_to_lock
和 std::adopt_lock
分别是空结构体标签类型 std::defer_lock_t 、 std::try_to_lock_t 和 std::adopt_lock_t 的实例。
它们用于为 std::lock_guard 、 std::unique_lock 及 std::shared_lock 指定锁定策略。
类型 | 效果 |
defer_lock_t | 不获得互斥的所有权 |
try_to_lock_t | 尝试获得互斥的所有权而不阻塞 |
adopt_lock_t | 假设调用方线程已拥有互斥的所有权 |
调用示例
#include <mutex>
#include <thread>
struct bank_account {
explicit bank_account(int balance) : balance(balance) {}
int balance;
std::mutex m;
};
void transfer(bank_account &from, bank_account &to, int amount)
{
// 锁定两个互斥而不死锁
std::lock(from.m, to.m);
// 保证二个已锁定互斥在作用域结尾解锁
std::lock_guard<std::mutex> lock1(from.m, std::adopt_lock);
std::lock_guard<std::mutex> lock2(to.m, std::adopt_lock);
// 等价方法:
// std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
// std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);
// std::lock(lock1, lock2);
from.balance -= amount;
to.balance += amount;
}
int main()
{
bank_account my_account(100);
bank_account your_account(50);
std::thread t1(transfer, std::ref(my_account), std::ref(your_account), 10);
std::thread t2(transfer, std::ref(your_account), std::ref(my_account), 5);
t1.join();
t2.join();
}