C++ monitor class/wrapper using condition variables

穿精又带淫゛_ 提交于 2021-02-19 06:07:05

问题


I'm trying to create a wrapper class W in C++, which is constructed with a pointer to a generic object OBJ.

When you call one of OBJ methods through W, W (containing a condition variable cv) issues a cv.wait() before calling OBJ method and a cv.notify() when OBJ method has finished.

I've been able to do it with inheritance for a specific class, but would like a generic approach like the one described above.

This is the inheritance approach:

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;
};

I would like something in like:

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;
};

I found an answer using only locks (but that is not really a monitor): https://stackoverflow.com/a/48408987


回答1:


Here is a working example:

#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();
}

Outputs:

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

See Wrapping C++ Member Function Calls by Bjarne Stroustrup for full details.




回答2:


It's not great, but what you can do is have a single function the user calls from the wrapper and you supply a lambda that calls the function they actually want to use. This makes it more verbose to use the wrapper but it allows you to wrap any type without trying to figure out how to forward all of its functions (something that really needs refelection to do generically). That would give you a wrapper like

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;
};

and then you would use it like

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

and that will call func_I_want_to_call on t from the wrapper with the supplied arguments.



来源:https://stackoverflow.com/questions/57857403/c-monitor-class-wrapper-using-condition-variables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!