跨不同回调函数管理std::unique_lock加解锁的实现方案咨询
实现方案
直接通过std::unique_lock的移动语义将锁的所有权转移到类成员变量即可,符合C++标准设计语义,同时保证异常安全,完整实现如下:
#include <mutex> #include <condition_variable> // 第三方提供的Foo类定义,无需修改 class Foo { public: void bar() { before_bar_callback(); // 第三方内部逻辑 after_bar_callback(); } private: virtual void before_bar_callback() {} virtual void after_bar_callback() {} }; class MyFoo : public Foo { private: bool flag = false; std::mutex mtx; std::condition_variable cond; // 用于持有跨两个回调的锁实例 std::unique_lock<std::mutex> held_lock; void before_bar_callback() override { std::unique_lock<std::mutex> local_lock(mtx); // 等待条件触发,自带谓词可规避虚假唤醒问题 cond.wait(local_lock, [&]{ return flag; }); // 转移锁所有权到成员变量,本地锁离开作用域不会释放 held_lock = std::move(local_lock); // ... 此处放置原有do some stuff逻辑 } void after_bar_callback() override { // ... 此处放置原有do some more stuff逻辑 flag = false; // 主动释放锁,也可省略等待held_lock析构时自动释放 held_lock.unlock(); } public: // 对外提供触发接口,由其他线程调用唤醒等待逻辑 void notify() { std::lock_guard<std::mutex> lock(mtx); flag = true; cond.notify_one(); } };
说明
std::unique_lock本身支持所有权转移,存储为类成员变量完全符合设计语义,由于before_bar_callback和after_bar_callback由Foo::bar所在的同一个线程顺序调用,不存在并发操作held_lock的情况,线程安全。- 异常安全保障:即使
Foo::bar在两个回调之间的内部逻辑抛出异常,MyFoo对象析构时会自动调用held_lock的析构函数释放互斥锁,不会出现死锁。 - 无需修改第三方
Foo类的任何实现,仅通过继承重写虚函数即可满足需求。
内容的提问来源于stack exchange,提问作者peter
相关产品推荐
相关产品推荐

