mutex 通用互斥管理

通用互斥管理

名称 描述
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 
#include 
#include 
 
int g_i = 0;
std::mutex g_i_mutex;  // 保护 g_i
 
void safe_increment()
{
    std::lock_guard 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 
#include 
#include 
#include 

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 lock1(from.m, std::defer_lock);
    std::unique_lock 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 
#include 
#include 

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 lock1(from.m, std::adopt_lock);
    std::lock_guard lock2(to.m, std::adopt_lock);

    // 等价方法:
    //    std::unique_lock lock1(from.m, std::defer_lock);
    //    std::unique_lock 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


相关参考

微软文档(mutex)

cppreference(mutex)

你可能感兴趣的:(mutex 通用互斥管理)