std::lock_guard

来自cppreference.com
< cpp‎ | thread
 
 
并发支持库
线程
(C++11)
(C++20)
(C++20)
this_thread 命名空间
(C++11)
(C++11)
(C++11)
互斥
(C++11)
(C++11)  
通用锁管理
(C++11)
lock_guard
(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 中弃用)
内存定序
原子操作的自由函数
原子标志的自由函数
 
std::lock_guard
 
在标头 <mutex> 定义
template< class Mutex >
class lock_guard;
(C++11 起)

lock_guard 是互斥体包装器,为在作用域块期间占有互斥体提供便利的 RAII 风格机制。

当创建 lock_guard 对象时,它尝试接收给定互斥体的所有权。当控制离开创建 lock_guard 对象的作用域时,销毁 lock_guard 并释放互斥体。

lock_guard 类不可复制。

模板形参

Mutex - 要锁定的互斥体。类型必须满足可基本锁定 (BasicLockable) 要求

成员类型

成员类型 定义
mutex_type Mutex

成员函数

构造 lock_guard,可选地锁定给定的互斥体
(公开成员函数)
析构 lock_guard 对象,解锁底层互斥体
(公开成员函数)
operator=
[弃置]
不可复制赋值
(公开成员函数)

注解

一种常见的新手错误是“忘记”给 lock_guard 变量命名,例如 std::lock_guard(mtx);(它默认构造了一个名为 mtxlock_guard 变量,或者 std::lock_guard{mtx};(它构造了一个纯右值对象并立即销毁),而并未真正为作用域的剩余部分构造持有互斥体的锁。

std::scoped_lock 给出 lock_guard 的一种替代,用避免死锁的算法提供锁定多个互斥体的能力。

(C++17 起)

示例

演示两个线程安全和不安全地增加一个 volatile 变量

#include <iostream>
#include <mutex>
#include <string_view>
#include <syncstream>
#include <thread>
 
volatile int g_i = 0;
std::mutex g_i_mutex;  // 保护 g_i
 
void safe_increment(int iterations)
{
    const std::lock_guard<std::mutex> lock(g_i_mutex);
    while (iterations-- > 0)
        g_i = g_i + 1;
    std::cout << "线程 #" << std::this_thread::get_id() << ", g_i: " << g_i << '\n';
 
    // g_i_mutex 在锁离开作用域时自动释放
}
 
void unsafe_increment(int iterations)
{
    while (iterations-- > 0)
        g_i = g_i + 1;
    std::osyncstream(std::cout) << "线程 #" << std::this_thread::get_id()
                                << ", g_i: " << g_i << '\n';
}
 
int main()
{
    auto test = [](std::string_view fun_name, auto fun)
    {
        g_i = 0;
        std::cout << fun_name << ":\n前, g_i: " << g_i << '\n';
        {
            std::jthread t1(fun, 1'000'000);
            std::jthread t2(fun, 1'000'000);
        }
        std::cout << "后, g_i: " << g_i << "\n\n";
    };
    test("safe_increment", safe_increment);
    test("unsafe_increment", unsafe_increment);
}

可能的输出:

safe_increment:
前, g_i: 0
线程 #140121493231360, g_i: 1000000
线程 #140121484838656, g_i: 2000000
后, g_i: 2000000
 
unsafe_increment:
前, g_i: 0
线程 #140121484838656, g_i: 1028945
线程 #140121493231360, g_i: 1034337
后, g_i: 1034337

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 2981 C++17 曾提供来自 lock_guard<Mutex> 的冗余推导指引 已移除

参阅

实现可移动的互斥体所有权包装器
(类模板)
用于多个互斥体的免死锁 RAII 封装器
(类模板)