◐ Shell
clean mode source ↗

std::lock_guard - cppreference.com

来自cppreference.com

template< class Mutex >
class lock_guard;
(C++11 起)

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

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

lock_guard 类不可复制。

模板形参

成员类型

成员函数

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

注解

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

示例

演示两个线程安全和不安全地增加一个 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> 的冗余推导指引 已移除

参阅