cpp unique_lock

本文介绍了C++中的RAII(Resource Acquisition Is Initialization)原则,通过std::unique_lock来管理和控制互斥锁(mutex)。在RAII中,资源的生命周期与对象的生命周期绑定,确保在对象创建时获取资源,在对象销毁时释放资源。在示例中,std::unique_lock在代码块内有效,用于保护共享变量的安全访问,当退出代码块时,锁会自动释放,避免了资源泄露。这种方式在异常安全性和内存管理上具有显著优势。

std::unique_lock use the RAII pattern.
RAII 即 资源获取是初始化(Resource acquisition is initialization),在 RAII 中,持有资源是类不变量,并且与对象生命周期相关联。资源分配(或获取)在对象创建(特别是初始化)期间由构造函数完成,而资源释放(释放)在对象销毁(特别是终结)期间由析构函数完成. 换句话说,资源获取必须成功,初始化才能成功。因此,资源被保证在初始化完成和终结开始之间被持有(持有资源是一个类不变量),并且只在对象处于活动状态时被持有。

上面可以理解为锁会在unique_lock存在范围内有效,一旦unique_lock范围结束,锁会释放。

如果要锁一个mutex变量,要创建一个std::unique_lock的局部变量,mutex作为参数。
unique_lock被创建时mutex会被锁住,unique变量析构时锁会释放。
如果发生了exception, unique_lock也会析构,mutex锁会释放。

示例:
unique_lock的有效范围在block内,block结束时,对my_mutex的锁会释放。

#include<mutex>
int some_shared_var=0;

int 
### 连续使用 `std::unique_lock` 的行为分析 在 C++ 中,连续使用 `std::unique_lock` 对象时,其行为取决于具体的构造方式和使用场景。以下是对该问题的详细分析: #### 1. **重复创建 `std::unique_lock` 对象** 如果在同一接口中连续创建多个 `std::unique_lock` 对象,并且这些对象绑定到同一个互斥锁上,则会导致重复锁定的问题[^2]。这是因为每个 `std::unique_lock` 对象在默认构造时会立即尝试锁定互斥锁,而互斥锁允许被重复锁定。 示例代码展示错误用法: ```cpp std::mutex mtx; void incorrectUsage() { std::unique_lock<std::mutex> lock1(mtx); // 第一次锁定 std::unique_lock<std::mutex> lock2(mtx); // 错误:尝试再次锁定相同的互斥锁 } ``` #### 2. **手动控制锁状态** 为了实现灵活的锁管理,可以使用 `std::defer_lock` 构造 `std::unique_lock` 对象,避免在构造时立即锁定互斥锁。随后,可以通过调用 `lock()` 和 `unlock()` 方法手动控制锁的状态[^3]。 示例代码展示正确用法: ```cpp std::mutex mtx; void correctUsage() { std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟锁定 lock.lock(); // 手动锁定 // 执行受保护的操作 lock.unlock(); // 手动解锁 // 其他操作 lock.lock(); // 再次锁定 // 执行更多受保护的操作 } ``` #### 3. **线程安全性分析** 当连续使用 `std::unique_lock` 时,必须确保会出现死锁或竞争条件。以下是一些关键点: - 如果多个线程同时尝试锁定同一个互斥锁,可能会导致死锁或线程阻塞[^2]。 - 使用 `std::try_lock()` 或 `std::try_to_lock` 可以避免阻塞,但需要开发者显式处理锁获取失败的情况[^4]。 示例代码展示非阻塞锁尝试: ```cpp std::mutex mtx; void tryLockExample() { std::unique_lock<std::mutex> lock(mtx, std::try_to_lock); // 尝试锁定 if (lock.owns_lock()) { // 检查是否成功获取锁 // 执行受保护的操作 } else { // 处理锁获取失败的情况 } } ``` #### 4. **与条件变量结合使用** 在多线程编程中,`std::unique_lock` 常与条件变量结合使用。此时,连续使用 `std::unique_lock` 必须确保正确传递给 `wait()` 函数,以避免线程阻塞或错过信号[^2]。 示例代码展示条件变量的正确用法: ```cpp std::mutex mtx; std::condition_variable cv; bool ready = false; void waitForCondition() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, [] { return ready; }); // 等待条件变量 // 条件满足后执行操作 } ``` #### 5. **锁的所有权转移** `std::unique_lock` 支持通过移动语义转移锁的所有权。这允许将锁对象从一个作用域传递到另一个作用域,而会导致重复锁定或资源泄漏[^3]。 示例代码展示锁的所有权转移: ```cpp std::mutex mtx; std::unique_lock<std::mutex> acquireLock() { return std::unique_lock<std::mutex>(mtx); // 返回锁对象 } void transferOwnership() { auto lock = acquireLock(); // 接收锁对象 // 执行受保护的操作 } ``` ### 注意事项 - **避免重复锁定**:在同一接口中多次创建 `std::unique_lock` 对象可能导致重复锁定问题,需谨慎处理。 - **延迟锁定的使用**:当需要手动控制锁的状态时,推荐使用 `std::defer_lock` 构造锁对象。 - **条件变量的正确使用**:在与条件变量结合使用时,确保传递正确的 `std::unique_lock` 对象以避免线程阻塞或错过信号。 - **异常安全性**:`std::unique_lock` 在超出作用域时会自动释放持有的互斥锁,从而保证异常安全性。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蓝羽飞鸟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值