通用互斥管理
名称 | 描述 |
---|---|
lock_guard | 实现严格基于作用域的互斥体所有权包装器 |
scoped_lock | 用于多个互斥体的免死锁 RAII 封装器 |
unique_lock | 实现可移动的互斥体所有权包装器 |
shared_lock | 实现可移动的共享互斥体所有权封装器 |
defer_lock_t try_to_lock_t adopt_lock_t |
用于指定锁定策略的标签类型 |
defer_lock try_to_lock adopt_lock |
用于指定锁定策略的标签常量 |
lock_guard
类 lock_guard 是互斥封装器,为在作用域块期间占有互斥提供便利 RAII 风格机制。
创建 lock_guard 对象时,它试图接收给定互斥的所有权。控制离开创建 lock_guard 对象的作用域时,销毁 lock_guard 并释放互斥。
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';
}
Output |
---|
main: 0 7884: 1 26220: 2 main: 2 |
unique_lock
类 unique_lock 是通用互斥包装器,允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用。
类 unique_lock 可移动,但不可复制——它满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 。
类 unique_lock 满足基础可锁 (BasicLockable) 要求。若 Mutex 满足可锁 (Lockable) 要求,则 unique_lock 亦满足可锁 (Lockable) 要求(例如:能用于 std::lock ) ;若 Mutex 满足定时可锁 (TimedLockable) 要求,则 unique_lock 亦满足定时可锁 (TimedLockable) 要求。
成员函数
名称 | 描述 |
---|---|
lock | 锁定关联互斥 |
try_lock | 尝试锁定关联互斥,若互斥不可用则返回 |
try_lock_for | 试图锁定关联的定时可锁 (TimedLockable) 互斥,若互斥在给定时长中不可用则返回 |
try_lock_until | 尝试锁定关联可定时锁 (TimedLockable) 互斥,若抵达指定时间点互斥仍不可用则返回 |
unlock | 解锁关联互斥 |
swap | 与另一 std::unique_lock 交换状态 |
release | 将关联互斥解关联而不解锁它 |
mutex | 返回指向关联互斥的指针 |
owns_lock | 测试锁是否占有其关联互斥 |
#include <iostream>
#include <mutex>
#include <thread>
#include <chrono>
struct Box {
explicit Box(int num) : num_things{ num } {}
int num_things;
std::mutex m;
};
void transfer(Box& from, Box& to, int num)
{
// 仍未实际取锁
std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);
// 锁两个 unique_lock 而不死锁
std::lock(lock1, lock2);
from.num_things -= num;
to.num_things += num;
// 'from.m' 与 'to.m' 互斥解锁于 'unique_lock' 析构函数
}
int main()
{
Box acc1(100);
Box acc2(50);
std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);
std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);
t1.join();
t2.join();
// Box1 = 100 - 10 + 5
// Box2 = 50 + 10 - 5
std::cout << "Box1:" << acc1.num_things << " Box2:" << acc2.num_things << std::endl;
}
Output |
---|
Box1:95 Box2:55 |
defer_lock, try_to_lock, adopt_lock
类型 | 效果 |
---|---|
defer_lock_t | 不获得互斥的所有权 |
try_to_lock_t | 尝试获得互斥的所有权而不阻塞 |
adopt_lock_t | 假设调用方线程已拥有互斥的所有权 |
#include <iostream>
#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();
std::cout << "my_account:" << my_account.balance << " your_account:" << your_account.balance << std::endl;
}
Output |
---|
my_account:95 your_account:55 |