我希望有一个接收互斥量类型作为模板参数的类,以(有条件地)保证线程安全。如果互斥锁类型等于NoMutex(我的互斥锁为空实现),则我不想将此互斥锁成员添加到类中,这样可以节省空间。 我想做这样的事情:
class NoMutex{
// Same interface as std::mutex but empty implementation
// so optimization can remove unnecessary function calls
};
template <class Mutex>
class MyClass {
public:
// Actually I want to hide it somehow. I dont want it to occupy any space if Mutex == NoMutex
some_template_trick<std::is_same_v<Mutex, NoMutex, void, Mutex> mutex;
void someFunction(){
std::unique_lock<Mutex> l(getMutex()); // I want to use std::unique_lock here
// do some concurrent stuff
}
Mutex& getMutex(){
if constexpr(std::is_same_v<Mutex, NoMutex>){
//ok... return reference to temporary is wrong, but i'm hopping
//that gcc will realize there is nothing to be done once all implementations
//are empty.
return NoMutex();
}
return mutex;
}
};
我不想专门化类,也不想创建lock()unlock()方法,我希望它们由std :: unique_lock();来管理。 有可能吗?
谢谢!
答案 0 :(得分:3)
空数据成员。也就是说,尽管无状态类的大小为非零(至少1个字节),但是如果用作基类,则不会消耗额外的内存:
template <typename Mutex>
struct CompressedMutex
{
Mutex mutex;
Mutex& getMutex() { return mutex; }
};
template <>
struct CompressedMutex<NoMutex> : NoMutex
{
NoMutex& getMutex() { return *this; }
};
template <typename Mutex>
class MyClass : CompressedMutex<Mutex>
{
public:
void someFunction()
{
std::unique_lock<Mutex> l(this->getMutex());
}
};
请注意,访问作为相关名称的this->
时需要CompressedMutex<Mutex>::
或getMutex()
。
但是,通常,人们希望在const
限定的成员函数中也锁定互斥量。为此,可以在互斥量数据成员的定义中使用mutable
关键字。在NoMutex
情况下,需要使用const_cast<CompressedMutex&>(*this)
或声明返回的static
对象:
template <typename Mutex>
struct CompressedMutex
{
mutable Mutex mutex;
Mutex& getMutex() const { return mutex; }
};
template <>
struct CompressedMutex<NoMutex>
{
static NoMutex mutex;
NoMutex& getMutex() const { return mutex; }
};
此技术已在标准库中广泛使用,因此无状态分配器(包括std::allocator<T>
)不占容器的总大小。这些对象通常存储在所谓的压缩对(例如boost::compressed_pair
)或其变体中,有时与非空数据成员一起存储,以便封闭类的接口可以不变:
#include <boost/compressed_pair.hpp>
template <typename Mutex>
class MyClass
{
public:
void someFunction()
{
std::unique_lock<Mutex> l(data.second());
}
private:
boost::compressed_pair<SomeDataMemberType, Mutex> data;
};
答案 1 :(得分:0)
您可以使用包含一两个东西(未测试的代码)的结构包装器来执行此操作:
template <class T1, class T2> class Pair {
Pair (const T1 &t1, const T2 &t2) : t1_(t1), t2_(t2) {}
T1 & first () { return t1_; }
T2 & second () { return t2_; }
T1 t1_;
T2 t2_;
};
template <class T1> class Pair<T1, NoMutex> {
Pair (const T1 &t1) : t1_(t1) {}
T1 & first () { return t1_; }
NoMutex second () { return NoMutex(); }
T1 t1_;
};