我想用一个互斥锁包装一个类实例的所有用法。今天我有
std::map<int, std::shared_ptr<MyClass>> classes;
以及查找和返回实例的函数,例如:
std::shared_ptr<MyClass> GetClass(int i);
我想确保GetClass()只能在其他人尚未检索到实例的情况下检索实例,并使用一些RAII机制。用法如下:
void CallingFunction()
{
auto c = GetClass(i); // mutex for class id 'i' is acquired here
// some calls to class
c.SomeFunction();
} // mutex is released here when 'c' goes out of scope
使用CallingFunction()获取的互斥锁,其他想要访问同一个类实例的线程会阻止对GetClass()的调用。
我一直在寻找一些方法,例如使用包装类,如:
class ClassContainer
{
public:
std::shared_ptr<Class> c;
std::mutex m;
};
我将GetClass()修改为:
ClassContainer GetClass(int i);
但是我无法弄清楚std :: mutex应该保留在哪里,我尝试将它存储在地图中,然后再转向使用容器类:
std::map<int, std::pair<std::mutex, std::shared_ptr<MyClass<>>> classes;
但是效果不好,现在使用ClassContainer如何让ClassContainer锁定std :: mutex,如std :: lock_guard&lt;&gt;当调用者通过调用GetClass()获得一个时。
答案 0 :(得分:2)
我一直在寻找一些方法,例如使用包装类,如:
是的,这是正确的方法并且你很接近,但是你不能将mutex
本身保留在这个类中,只有锁定器。并且std::unique_lock
是适合的类型,因为它必须移动ctor等。我会将字段设为私有,并创建必要的访问者:
class ClassContainer
{
std::shared_ptr<Class> c;
std::uniqe_lock<mutex> lock;
public:
ClassContainer( std::pair<std::mutex,std::shared_ptr<Class>> &p ) :
c( p.second ),
lock( p.first )
{
}
Class * operator->()const { return c.get(); }
Class & operator*() const { return *c; }
};
然后用法很简单:
void CallingFunction()
{
auto c = GetClass(i); // mutex for class id 'i' is acquired here
// some calls to class
c->SomeFunction();
// or even
GetClass(i)->SomeFunction();
}
答案 1 :(得分:1)
Class
应保留mutex
,例如:
class Class
{
public:
// Your methods...
std::mutex& GetMutex() { return m; }
private:
std::mutex m;
};
class ClassContainer
{
public:
ClassContainer(std::shared_ptr<Class> c) :
c(std::move(c)),
l(this->c->GetMutex())
{}
ClassContainer(const ClassContainer&) = delete;
ClassContainer(ClassContainer&&) = delete;
ClassContainer& operator =(const ClassContainer&) = default;
ClassContainer& operator =(ClassContainer&&) = default;
// For transparent pointer like access to Class.
decltype(auto) operator -> () const { return c; }
decltype(auto) operator -> () { return c; }
const Class& operator*() const { return *c; }
Class& operator*() { return *c; }
private:
std::shared_ptr<Class> c;
std::lock_guard<std::mutex> l;
};
ClassContainer GetClass(int i)
{
auto c = std::make_shared<Class>();
return {c}; // syntax which avoids copy/move contructor.
}
最后用法:
auto&& cc = GetClass(42); // `auto&&` or `const&` pre-C++17, simple auto possible in C++17
cc->ClassMethod();
答案 2 :(得分:0)
不小心,我最近做了一些非常相似的事情(只是我返回了对象而不是shared_ptr
的引用。代码的作用如下:
struct locked_queue {
locked_queue(locked_queue&& ) = default;
mutable std::unique_lock<decltype(queue::mutex)> lock;
const queue::q_impl_t& queue; // std::deque
};
以下是它的使用方法:
locked_queue ClassX::get_queue(...) {
return {std::unique_lock<decltype(mutex)>{mutex}, queue_impl};
}