C++常用容器、函数、类集(7)

接前一篇文章:C++常用容器、函数、类集(6)

本文内容参考:

std::lock_guard 详解_stdlockguard-优快云博客

std::lock_guard的介绍(包含使用示例)_c++ lockguard-优快云博客

特此致谢!

16. std::lock_guard

std::lock_guard是C++11标准库中的一个类模板,用于自动管理互斥锁(std::mutex或其派生类的锁定和解锁)。其主要目的是提供一种简便且安全的方式来保护临界区(critical sections)免受数据竞争(data race)的影响。它利用了RAII(资源获取即初始化)技术,确保在作用域结束时自动释放锁。

主要特性

  • 自动加锁和解锁

当std::lock_guard对象被创建时,它会自动锁定提供的互斥锁。当该对象离开其作用域(即被销毁)时,它会自动解锁互斥锁。这种自动管理确保了即使在发生异常的情况下,互斥锁也能被正确解锁。

std::lock_guard的构造函数会自动调用互斥锁的lock方法来加锁;而析构函数会自动调用互斥锁的unlock方法来解锁。

  • 防止死锁

由于std::lock_guard会在析构时自动释放锁,因此可以有效避免因忘记手动解锁而导致的死锁问题。

  • 简单易用

std::lock_guard的使用非常简单,只需要在需要保护的代码块之前创建它即可。无需显式调用锁定和解锁函数。

  • 非递归

std::lock_guard不支持递归锁定,即不能多次锁定同一个互斥锁。如果尝试这样做,会导致未定义的行为。

  • 异常安全

std::lock_guard提供了异常安全性,即使在临界区代码中抛出异常,互斥锁也能被正确解锁。这是因为它在析构函数中解锁互斥锁,而析构函数在异常处理期间也会被调用。

使用方法

使用std::lock_guard的基本步骤如下:

1)包含头文件

首先,需要包含<mutex>头文件以使用std:lock_guard和相关的互斥锁类型。

#include <mutex>

2)定义互斥锁

在需要保护的代码段之前或附近定义一个std::mutex对象。

std::mutex mtx;

3)使用std::lock_guard

在需要保护的代码块之前创建std::lock_guard对象,并将互斥锁作为参数传递给它。

{
    std::lock_guard<std::mutex> guard(mtx);
    // 临界区代码,此时 mtx 被锁定
    // ...
} // 当 guard 对象离开作用域时,mtx 会被自动解锁

完整代码示例如下:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void print_thread_id(int id) {
    std::lock_guard<std::mutex> lock(mtx); // 自动加锁
    std::cout << "Thread #" << id << " is running\n";
} // lock_guard 析构,自动解锁

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i) {
        threads[i] = std::thread(print_thread_id, i + 1);
    }
    for (auto& th : threads) {
        th.join();
    }
    return 0;
}

也可以采用“已加锁”方式,代码示例如下:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void print_thread_id(int id) {
    mtx.lock(); // 手动加锁
    std::lock_guard<std::mutex> lock(mtx, std::adopt_lock); // 采用已加锁
    std::cout << "Thread #" << id << " is running\n";
} // lock_guard 析构,自动解锁

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i) {
        threads[i] = std::thread(print_thread_id, i + 1);
    }
    for (auto& th : threads) {
        th.join();
    }
    return 0;
}

注意事项

  • 不要手动解锁

使用std::lock_guard时,不需要(也不应该)手动调用解锁函数。std::lock_guard会在其析构函数中自动解锁互斥锁。

  • 避免递归锁定

std::lock_guard不支持递归锁定。如果尝试多次锁定同一个互斥锁,会导致未定义的行为。

  • 避免在循环中使用

由于std::lock_guard在其析构函数中解锁互斥锁,因此如果在循环中创建和销毁它,可能会导致性能下降。在这种情况下,考虑使用std::unique_lock,它允许在循环中保持锁定状态。

  • 不要拷贝或移动

std::lock_guard的拷贝构造和移动构造都被禁用,因此不能拷贝或移动std::lock_guard对象。

  • 更复杂场景

如果需要更复杂的锁管理(如尝试加锁、定时加锁、循环加锁等),可以使用std::unique_lock。

更多内容请看下回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝天居士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值