C++ 监视器 class/wrapper 使用条件变量

C++ monitor class/wrapper using condition variables

我正在尝试用 C++ 创建包装器 class W,它是用指向通用对象的指针构建的 OBJ

当您通过 W 调用 OBJ 方法之一时,W(包含条件变量 cv)在调用 OBJ 方法和 cv.notify()OBJ 方法完成时。

我已经能够通过特定 class 的继承来做到这一点,但我想要一种像上面描述的那样的通用方法。

这是继承方式:

struct A
{
    virtual void foo(int i) { bar = i; };
    int bar;
};

struct B : public A
{
    void foo2(int i)
    {
        cv.wait(lck);
        this->foo(i);
        cv.notify_one();
    }
    std::condition_variable cv;
    std::unique_lock<std::mutex> lck;
};

我想要类似的东西:

template<class T>
struct C
{
    C(T *t) : t(t) {}

    T *operator->()
    {
        cv.wait(lck);
        return t;
        // notify_one when function has completed
    }

    T *t;
    std::condition_variable cv;
    std::unique_lock<std::mutex> lck;
};

我找到了一个只使用锁的答案(但那不是真正的监视器):

这不是很好,但是您可以做的是让用户从包装器调用一个函数,然后您提供一个 lambda 来调用他们实际想要使用的函数。这使得使用包装器变得更加冗长,但它允许您包装任何类型,而无需试图弄清楚如何转发其所有功能(这确实需要反射才能通用)。那会给你一个像

这样的包装器
template<class T>
struct C
{
    C(T *t) : t(t) {}

    template<typename Func>
    void call(Func func)
    {
        wait operation
        func(t);
        notify operation
    }

    T *t;
};

然后你会像

一样使用它
Foo_ptr foo =  ...;
C wrapper(foo);
wrapper.call([](auto ptr){ return ptr->func_I_want_to_call(arguments); });

这将使用提供的参数从包装器调用 t 上的 func_I_want_to_call

这是一个工作示例:

#include <iostream>
#include <mutex>

template<class T>
class Wrapper {
    std::mutex m;
    T* p;

public:
    Wrapper(T& t) : p(&t) {}

    class Proxy {
        std::unique_lock<std::mutex> lock;
        T* p;

    public:
        Proxy(std::mutex& m, T* p)
            : lock(m)
            , p(p)
        {
            // Locked the mutex.
            std::cout << __PRETTY_FUNCTION__ << '\n';
        }

        Proxy(Proxy&& b) = default;

        ~Proxy() {
            std::cout << __PRETTY_FUNCTION__ << '\n';
            // Unlocked the mutex.
        }

        T* operator->() const { return p; }
    };

    Proxy operator->() { return Proxy(m, p); }
};

struct A {
    void f() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
};

int main() {
    A a;
    Wrapper<A> w(a);
    w->f();
}

输出:

Wrapper<T>::Proxy::Proxy(std::mutex&, T*) [with T = A]
void A::f()
Wrapper<T>::Proxy::~Proxy() [with T = A]

有关详细信息,请参阅 Wrapping C++ Member Function Calls by Bjarne Stroustrup