明智的互联网
我们在两位同事之间陷入僵局,我们可以使用您的帮助以正确的C ++方式解决问题。基本上我们有一组实用程序类,其中两个是Mutex和SpinLock类,它们都有以下删节接口:
class Mutex {
public:
Mutex();
~Mutex();
void Lock();
void Unlock();
// ...
};
显然这与std :: lock_guard使用的BasicLockable概念类似但不同,所以我们想要类似的东西(假设Mutex类在这个例子中是不可变的;我们不能向它添加BasicLockable概念) 。此外,并非我们所有支持平台的编译器都是完全c ++ 11特色,所以我们不能只使用vanilla c ++ 11支持。
一个思想流派是一个通用保护类的以下实现,它可以被继承以提供通用保护类并从中继承以创建一个锁定保护类:
template<class T, void (T::*EnterFn)(), void (T::*ExitFn)()>
class Guard
{
public: // copy constructor deleting omitted for brevity
Guard( T *lock ) : m_lock(lock) { (m_lock->*EnterFn)(); }
~Guard(); { (m_lock->*ExitFn)(); }
private:
T *m_lock;
};
template<class T>
class LockGuard : public Guard<T, &T::Lock, &T::Unlock>
{
public:
LockGuard(const T* lock) : Guard<T, &T::Lock, &T::Unlock>(lock) {}
};
另一种思想就是实施一个简单的锁定装置:
template<class T>
class LockGuard {
T* m_lockable;
public:
LockGuard(const T* lockable) : m_lockable(lockable) { lockable->Lock(); }
~LockGuard() { m_lockable->Unlock(); }
};
您会选择哪种实施方式?为什么?什么是最合适的C ++(03,11,14,17)实现方式?如上所述拥有通用Guard类是否有任何内在价值?
答案 0 :(得分:1)
我不想使用方法指针。
就个人而言,我希望尽可能地转向C ++ 11标准工具。所以我写了一个适配器。
template<class T>
struct lock_adapter {
T* t = nullptr;
void lock() { t->Lock(); }
void unlock() { t->Unlock(); }
lock_adapter( T& tin ):t(std::addressof(tin)) {}
// default some stuff if you like
};
template<class T>
struct adapted_unique_lock:
private lock_adapter<T>,
std::unique_lock< lock_adapter<T> >
{
template<class...Args>
adapted_unique_lock(T& t, Args&&...):
lock_adapter<T>(t),
std::unique_lock< lock_adapter<T> >( *this, std::forward<Args>(args)... )
{}
adapted_unique_lock(adapted_unique_lock&&)=delete; // sadly
friend void swap( adapted_unique_lock&, adapted_unique_lock& ) = delete; // ditto
};
现在adapted_unique_lock
来自std::unique_lock
的功能受限制。
无法移动,因为unique_lock
在其实现中包含指向this
的指针,并且不会重置它。
请注意,整个unique_lock
构造函数集的丰富性可用。
返回自适应唯一锁的函数必须将它们的返回值存储在auto&&
引用之类的内容中,直到作用域结束,并且在C ++ 17之前不能通过链返回它们。
但是,在adapted_unique_lock
更改为支持unique_lock
和T
后,使用.lock()
的所有代码都可以交换使用.unlock()
。这将您的代码库转移到更标准的C ++ 11,而不是定制。
答案 1 :(得分:1)
我会在您的标题中回答这个问题,因为没有人回答。
根据the docs,lock_guard
适用于“满足BasicLockable
要求”的任何类型。 BasicLockable仅需要两种方法lock()
和unlock()
。
为了使lock_guard
与自定义库一起使用,您需要将lock()
和unlock()
方法添加到该库的互斥体类中,或将其包装在另一个具有{ {1}}和lock()
方法。
答案 2 :(得分:0)
你应该使用:std :: mutex,std :: shared_lock,std :: unique_lock, std :: timed_mutex,std :: shared_mutex,std :: recursive_mutex,std :: shared_timed_mutex,std :: recursive_timed_mutex,std :: lock_guard如果你真的有C ++ 11编译器。否则它会更复杂,应该删除有问题的标签c ++ 11。
你不能用C \ C ++实现自旋锁或互斥,意味着你需要添加汇编程序或内部代码 - 使它不可移植,除非你为每个平台实现它 - 并且有很多x86-64 C ++ 11及更高版本的编译器,你不能做内联汇编程序。
如果使用固有锁定逻辑,您将遇到的主要问题是互斥锁或自旋锁后面的对象是不可复制的。一旦复制它或复制了防御变量,它就会停止被锁定。实现互斥机制的对象也是不可复制的。