命名空间
变体
操作

std::lock

来自 cppreference.cn
< cpp‎ | thread
 
 
并发支持库
线程
(C++11)
(C++20)
this_thread 命名空间
(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)
Hazard Pointers
原子类型
(C++11)
(C++20)
原子类型的初始化
(C++11)(在 C++20 中已弃用)
(C++11)(在 C++20 中已弃用)
内存顺序
(C++11)(在 C++26 中已弃用)
原子操作的自由函数
原子标志的自由函数
 
定义于头文件 <mutex>
template< class Lockable1, class Lockable2, class... LockableN >
void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn );
(since C++11)

使用死锁避免算法锁定给定的 Lockable 对象 lock1, lock2, ..., lockn 以避免死锁。

这些对象通过对 locktry_lockunlock 的未指明系列调用来锁定。如果对 lockunlock 的调用导致异常,则在重新抛出之前,将为任何已锁定对象调用 unlock

目录

[edit] 参数

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

[edit] 返回值

(无)

[edit] 注释

Boost 提供了此函数的版本,该版本接受由一对迭代器定义的 Lockable 对象序列。

std::scoped_lock 为此函数提供了 RAII 包装器,并且通常优于对 std::lock 的裸调用。

[edit] 示例

以下示例使用 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&)
{
    // Simulate a time-consuming messaging operation
    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;
    }
 
    // Use std::lock to acquire two locks without worrying about 
    // other calls to assign_lunch_partner deadlocking us
    {
        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);
    // Equivalent code (if unique_locks are needed, e.g. for condition variables)
    //  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);
    // Superior solution available in 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");
 
    // Assign in parallel threads because mailing users about lunch assignments
    // takes a long time
    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
Dave and Bob are waiting for locks
Dave and Bob got locks
Christina and Alice 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

[edit] 参见

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