问题
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