# std::lock

< cpp‎ | thread

定义于头文件 `<mutex>` |  |
template< class Lockable1, class Lockable2, class... LockableN > void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn ); |  | (C++11 起)

锁定给定的可锁定 (Lockable) 对象 `lock1` 、 `lock2` 、 `...` 、 `lockn` ，用免死锁算法避免死锁。

以对 `lock` 、 `try_lock` 和 `unlock` 的未指定系列调用锁定对象。若调用 `lock` 或 `unlock` 导致异常，则在重抛前对任何已锁的对象调用 `unlock` 。

### 参数

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

### 返回值

（无）

### 注意

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

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

### 示例

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

    #include <mutex>
    #include <thread>
    #include <iostream>
    #include <vector>
    #include <functional>
    #include <chrono>
    #include <string>

    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 = "Employee " + id + " has lunch partners: ";
            for( const auto& partner : lunch_partners )
                ret += partner + " ";
            return ret;
        }
    };

    void send_mail(Employee &, Employee &)
    {
        // 模拟耗时的发信操作
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    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 << " and " << e2.id << " are waiting for locks" << 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 << " and " << e2.id << " got locks" << 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 and bob are waiting for locks
    alice and bob got locks
    christina and bob are waiting for locks
    christina and bob got locks
    christina and alice are waiting for locks
    christina and alice got locks
    dave and bob are waiting for locks
    dave and bob got locks
    Employee alice has lunch partners: bob christina
    Employee bob has lunch partners: alice christina dave
    Employee christina has lunch partners: bob alice
    Employee dave has lunch partners: bob

### 参阅

try_lock (C++11) | 试图通过重复调用 `try_lock` 获得互斥体的所有权 (函数模板)
scoped_lock (C++17) | 用于多个互斥体的免死锁 RAII 封装器 (类模板)