c++积累5-lock_guard使用

文章介绍了C++中std::mutex互斥量的作用,用于保护多线程环境中的共享数据,防止并发访问导致的问题。std::lock_guard是std::mutex的智能包装器,自动处理锁定和解锁,避免了手动管理锁可能导致的资源泄露。通过示例展示了未加锁和使用std::lock_guard后的程序行为差异,证明了std::lock_guard在确保线程安全方面的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、std:mutex

在了解lock_guard之前,需要先学习下std:mutex,因为lock_guard内部就是使用的std:mutex
std:mutex:是一个用于保护共享数据不会同时被多个线程访问的类,它叫做互斥量。我们可以把它看作一把锁,基本使用如下:

#include <mutex>

std::mutex kMutex;

void function() {
  //加锁
  kMutex.lock();
  //kMutex.try_lock();

  //do something that is thread safe...
  
  // 离开作用域解锁
  kMutex.unlock();
}

来看一个例子,两个线程共同访问一个全局变量
首先我们实现一个不加锁的看看有什么问题:


#include <iostream>
#include <thread>

int gData = 0;
std::mutex kMutex;

void increment(){
    for (int i = 0; i < 1000000; i++) {
        gData++;
        std::cout<< std::this_thread::get_id()  << ":"<< gData << std::endl;
    }
}

int main() {
    std::cout<< __FUNCTION__  << ":" << gData << std::endl;
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    getchar();

    return 0;
}

输出:
在这里插入图片描述
可以看到,结果并不是我们所期望的,那么我们使用mutex加上锁之后看下:


#include <iostream>
#include <thread>

int gData = 0;
std::mutex kMutex;

void increment(){
    kMutex.lock();
    for (int i = 0; i < 1000000; i++) {
        gData++;
        std::cout<< std::this_thread::get_id()  << ":"<< gData << std::endl;
    }
    kMutex.unlock();
}

int main() {
    std::cout<< __FUNCTION__  << ":" << gData << std::endl;
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    getchar();

    return 0;
}

输出:
在这里插入图片描述
我们可以看到加了锁之后呢,输出结果是正确的了

2、std:lock_guard

std:lock_guard 其实就是对std:mutex的一个包装类,能够实现自动unlock,而不必手动进行unlock操作。它在构造中完成加锁,在析构中完成解锁。
先让我们自己实现一个这样的类:

namespace myspace{
    template<typename T> class my_lock_guard{
    public:
        my_lock_guard(T& mutex):mutex_(mutex){
            // 构造加锁
            mutex_.lock();
        }

        ~my_lock_guard(){
            // 析构解锁
            mutex_.unlock();
        }

    private:
        // 不可赋值,不可拷贝
        my_lock_guard(my_lock_guard const&);
        my_lock_guard& operator=(my_lock_guard const&);

    private:
        T& mutex_;
    };
}

还是按照上面小节中的例子:


#include <iostream>
#include <thread>

int gData = 0;
std::mutex kMutex;

namespace myspace{
    template<typename T> class my_lock_guard{
    public:
        my_lock_guard(T& mutex):mutex_(mutex){
            // 构造加锁
            mutex_.lock();
        }

        ~my_lock_guard(){
            // 析构解锁
            mutex_.unlock();
        }

    private:
        // 不可赋值,不可拷贝
        my_lock_guard(my_lock_guard const&);
        my_lock_guard& operator=(my_lock_guard const&);

    private:
        T& mutex_;
    };
}

void increment(){
    myspace::my_lock_guard<std::mutex> myLockGuard(kMutex);

    for (int i = 0; i < 1000000; i++) {
        gData++;
        std::cout<< std::this_thread::get_id()  << ":"<< gData << std::endl;
    }
}

int main() {
    std::cout<< __FUNCTION__  << ":" << gData << std::endl;
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    getchar();

    return 0;
}

输出:
在这里插入图片描述
可以看到这里的输出也是正确的。

std::lock_guard原理跟这个也是一样的,我们看下它的源码:
在这里插入图片描述
例子代码:


#include <iostream>
#include <thread>

int gData = 0;
std::mutex kMutex;

namespace myspace{
    template<typename T> class my_lock_guard{
    public:
        my_lock_guard(T& mutex):mutex_(mutex){
            // 构造加锁
            mutex_.lock();
        }

        ~my_lock_guard(){
            // 析构解锁
            mutex_.unlock();
        }

    private:
        // 不可赋值,不可拷贝
        my_lock_guard(my_lock_guard const&);
        my_lock_guard& operator=(my_lock_guard const&);

    private:
        T& mutex_;
    };
}

void increment(){
    std::lock_guard<std::mutex> lockGuard(kMutex);

    for (int i = 0; i < 1000000; i++) {
        gData++;
        std::cout<< std::this_thread::get_id()  << ":"<< gData << std::endl;
    }
}

int main() {
    std::cout<< __FUNCTION__  << ":" << gData << std::endl;
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    getchar();

    return 0;
}

输出:
在这里插入图片描述
看结果也是正确的。

总结三个代码在例子中的不同处:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<think>嗯,用户想了解C++中std::lock_guard的用法和相关问题。首先,我需要回忆一下std::lock_guard的基本概念。它是RAII(资源获取即初始化)机制的一部分,用于管理互斥量的锁定和解锁,确保在作用域结束时自动释放锁,避免死锁。 接下来,我应该考虑用户可能的实际需求。他们可能想知道如何正确使用lock_guard,比如在函数中保护共享资源。需要给出一个简单的例子,比如在多线程环境中对共享变量的操作。 然后,用户可能对lock_guard与std::mutex的关系不太清楚,需要解释它们如何配合使用。同时,用户可能想知道lock_guard的作用域范围,以及为什么它不可复制或移动,这些特性如何帮助避免资源泄漏。 另外,用户提到的引用[1]中涉及了std::unique_lock使用,这可能暗示用户对不同类型的锁管理机制有疑问。需要比较lock_guard和unique_lock的区别,比如后者更灵活,支持延迟锁定和手动解锁,而前者更轻量,适用于简单的作用域锁定。 用户可能还需要了解lock_guard在异常安全中的作用,确保即使发生异常,互斥量也能正确释放。这可能涉及到在构造函数中锁定,析构函数中解锁的机制。 还要注意用户的问题中是否有关于多线程同步的其他方面,比如死锁避免,但根据问题,主要焦点应放在lock_guard使用上。可能需要提醒用户,当需要同时锁定多个互斥量时,应使用std::lock配合std::adopt_lock策略,或者使用std::scoped_lockC++17之后)。 最后,生成相关问题时要覆盖常见的使用场景、与其他锁的区别、异常安全以及实际应用中的例子。确保问题能引导用户进一步深入学习,并解决他们可能遇到的实际问题。</think>### C++ std::lock_guard用法与示例 `std::lock_guard`是C++标准库中实现RAII(资源获取即初始化)的锁管理工具,用于自动管理互斥锁(`std::mutex`)的加锁与解锁,避免因异常或代码分支导致的未解锁问题。 --- #### 1. 基本用法 `std::lock_guard`在构造时锁定互斥量,析构时自动释放锁。 **示例:保护共享变量** ```cpp #include <mutex> #include <thread> std::mutex mtx; int shared_data = 0; void increment() { std::lock_guard<std::mutex> lock(mtx); // 构造时加锁 shared_data++; // 受保护操作 // 离开作用域时自动解锁 } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); return 0; } ``` --- #### 2. 核心特性 - **作用域绑定**:锁的生命周期与作用域一致。 - **不可复制/移动**:确保锁的所有权唯一[^1]。 - **异常安全**:即使发生异常,锁也会正确释放。 --- #### 3. 与`std::unique_lock`对比 | 特性 | `std::lock_guard` | `std::unique_lock` | |--------------------|------------------------|-----------------------------| | 灵活性 | 仅支持自动加锁/解锁 | 支持手动加锁/解锁、延迟锁定 | | 性能开销 | 更低 | 略高 | | 适用场景 | 简单作用域锁 | 复杂同步逻辑(如条件变量) | --- #### 4. 注意事项 - **避免嵌套锁**:同一线程重复加锁可能导致死锁。 - **配合`std::lock`使用**:需同时锁多个互斥量时,优先使用`std::lock`: ```cpp std::mutex mtx1, mtx2; void safe_op() { std::lock(mtx1, mtx2); // 同时锁定两个互斥量 std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock); std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock); // 操作共享资源 } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值