You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于条件变量的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;
}

关键细节说明

  1. 代理对象的生命周期:当你写monitor->foo(42)时,Monitor::operator->()会返回一个MethodProxy临时对象,这个对象会在foo(42)执行完毕后立即被销毁,析构函数里的notify_one()刚好在方法执行完成后触发。
  2. 线程安全保障:每个Monitor实例持有自己的互斥量和条件变量,避免不同实例之间的锁竞争。
  3. 扩展性:如果需要等待特定条件(比如某个标志位为true),只需要修改MethodProxy构造函数里的cv.wait()调用,添加对应的谓词即可。

内容的提问来源于stack exchange,提问作者sornbro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:27:25