std::lock

来自cppreference.com
< cpp‎ | thread
 
 
并发支持库
线程
(C++11)
(C++20)
(C++20)
this_thread 命名空间
(C++11)
(C++11)
(C++11)
互斥
(C++11)
(C++11)  
通用锁管理
lock
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
条件变量
(C++11)
信号量
闩与屏障
(C++20)
(C++20)
未来体
(C++11)
(C++11)
(C++11)
(C++11)
安全回收
(C++26)
(C++26)
风险指针





原子类型
(C++11)
(C++20)
原子类型的初始化
(C++11)(C++20 中弃用)
(C++11)(C++20 中弃用)
内存定序
原子操作的自由函数
原子标志的自由函数
 
在标头 <mutex> 定义
template< class Lockable1, class Lockable2, class... LockableN >
void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn );
(C++11 起)

锁定给定的可锁定 (Lockable) 对象 lock1lock2...lockn,使用免死锁算法以避免死锁。

对象被一系列未指定的 locktry_lockunlock 调用锁定。若调用 lockunlock 导致异常,则在重抛前对任何已锁的对象调用 unlock

参数

lock1, lock2, ... , lockn - 要锁定的可锁定 (Lockable) 对象

返回值

(无)

注解

Boost 提供此函数的一个版本,它接收以一对迭代器定义的可锁定 (Lockable) 对象的序列。

std::scoped_lock 提供此函数的 RAII 包装,通常它比裸调用 std::lock 更好。

示例

下列示例用 std::lock 锁定互斥体对而不死锁。

#include <chrono>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
 
struct Employee
{
    Employee(std::string id) : id(id) {}
    std::string id;
    std::vector<std::string> lunch_partners;
    std::mutex m;
    std::string output() const
    {
        std::string ret = "雇员 " + id + " 的午餐伙伴: ";
        for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners)
            ret += partner + (--n ? ", " : "");
        return ret;
    }
};
 
void send_mail(Employee &, Employee &)
{
    // 模拟耗时的发信操作
    std::this_thread::sleep_for(std::chrono::milliseconds(696));
}
 
void assign_lunch_partner(Employee& e1, Employee& e2)
{
    static std::mutex io_mutex;
    {
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << e1.id << " 和 " << e2.id << " 正等待锁定" << std::endl;
    }
 
    // 用 std::lock 获得两个锁,而不担心对 assign_lunch_partner 的其他调用会死锁我们
    {
        std::lock(e1.m, e2.m);
        std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock);
        std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock);
    // 等价代码(若需要 unique_locks ,例如对于条件变量)
    //  std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock);
    //  std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock);
    //  std::lock(lk1, lk2);
    // C++17 中可用的较优解法
    //  std::scoped_lock lk(e1.m, e2.m);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << e1.id << " 和 " << e2.id << " 获得了锁" << std::endl;
        }
        e1.lunch_partners.push_back(e2.id);
        e2.lunch_partners.push_back(e1.id);
    }
    send_mail(e1, e2);
    send_mail(e2, e1);
}
 
int main()
{
    Employee alice("Alice"), bob("Bob"), christina("Christina"), dave("Dave");
 
    // 在平行线程指派,因为发邮件给用户告知午餐指派,会消耗长时间
    std::vector<std::thread> threads;
    threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));
    threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));
 
    for (auto& thread : threads)
        thread.join();
 
    std::cout << alice.output() << '\n'
              << bob.output() << '\n'
              << christina.output() << '\n'
              << dave.output() << '\n';
}

可能的输出:

Alice 和 Bob 正等待锁定
Alice 和 Bob 获得了锁
Christina 和 Bob 正等待锁定
Christina 和 Bob 获得了锁
Christina 和 Alice 正等待锁定
Dave 和 Bob 正等待锁定
Dave 和 Bob 获得了锁
Christina 和 Alice 获得了锁
雇员 Alice 的午餐伙伴: Bob, Christina 
雇员 Bob 的午餐伙伴: Alice, Christina, Dave 
雇员 Christina 的午餐伙伴: Bob, Alice 
雇员 Dave 的午餐伙伴: Bob

参阅

实现可移动的互斥体所有权包装器
(类模板)
(C++11)
尝试通过重复调用 try_lock 获得互斥体的所有权
(函数模板)
用于多个互斥体的免死锁 RAII 封装器
(类模板)