基于条件变量的C++通用对象监视器包装类实现问询
通用监视器包装类实现方案
嘿,你遇到的这个问题其实是通用监视器模式的典型需求——想给任意对象做一层包装,让调用它的方法时自动先等待条件变量,方法执行完再发送通知。你之前用继承实现特定类的思路没问题,但确实不够通用,而你尝试的模板方案卡在了没法追踪方法执行完毕的时机上,毕竟operator->返回原始指针后,控制权就交给调用者了,根本没机会在方法结束后调用notify_one()。
核心思路:用代理对象追踪方法生命周期
解决这个问题的关键是不要直接返回原始对象指针,而是返回一个临时代理对象。这个代理对象会在构造时完成cv.wait(),在自己的析构函数里调用cv.notify_one()——因为代理对象的生命周期刚好覆盖了方法调用的全过程,完美契合我们的需求。
完整通用实现代码
#include <condition_variable> #include <mutex> template <class T> struct Monitor { // 构造函数接收被包装对象的指针 explicit Monitor(T* wrapped_obj) : wrapped_obj_(wrapped_obj) {} // 代理类:负责处理wait和notify的逻辑 struct MethodProxy { MethodProxy(T* obj, std::condition_variable& cv, std::mutex& mtx) : target_obj_(obj), cv_(cv), lock_(mtx) { // 这里可以根据需求添加等待谓词,比如等待某个条件满足 // 示例是无限等待,你可以改成cv.wait(lock_, []{ return some_condition; }) cv_.wait(lock_); } // 析构时触发通知:此时方法已经执行完成 ~MethodProxy() { cv_.notify_one(); } // 重载->运算符,让用户能直接调用原对象的方法 T* operator->() { return target_obj_; } // 支持const方法调用的版本 const T* operator->() const { return target_obj_; } private: T* target_obj_; std::condition_variable& cv_; std::unique_lock<std::mutex> lock_; }; // 每次调用->时返回代理对象 MethodProxy operator->() { return MethodProxy(wrapped_obj_, cv_, mtx_); } // const版本的operator->,支持调用原对象的const方法 MethodProxy operator->() const { return MethodProxy(wrapped_obj_, const_cast<std::condition_variable&>(cv_), const_cast<std::mutex&>(mtx_)); } private: T* wrapped_obj_; std::condition_variable cv_; std::mutex mtx_; // 每个Monitor实例对应独立的互斥量,保证线程安全 };
怎么用这个包装类?
用法和你期望的一样简单,直接包装任意对象即可:
// 你的原始类A struct A { virtual void foo(int i) { bar = i; } int bar = 0; }; int main() { A a; Monitor<A> monitor(&a); // 调用方法时会自动先wait,执行完自动notify monitor->foo(42); // 此时a.bar已经是42,且notify_one()已经被调用 return 0; }
关键细节说明
- 代理对象的生命周期:当你写
monitor->foo(42)时,Monitor::operator->()会返回一个MethodProxy临时对象,这个对象会在foo(42)执行完毕后立即被销毁,析构函数里的notify_one()刚好在方法执行完成后触发。 - 线程安全保障:每个
Monitor实例持有自己的互斥量和条件变量,避免不同实例之间的锁竞争。 - 扩展性:如果需要等待特定条件(比如某个标志位为true),只需要修改
MethodProxy构造函数里的cv.wait()调用,添加对应的谓词即可。
内容的提问来源于stack exchange,提问作者sornbro
相关产品推荐
相关产品推荐

