Namespaces
Variants

std:: lock

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
lock
(C++11)
(C++11)
(C++11)
(C++11)
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
定义于头文件 <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 <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 = "Employee " + id + " has lunch partners: ";
        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 << " 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_lock,例如用于条件变量)
    //  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() <span class

参见

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