Tim*_* MB 14 c++ mutex smart-pointers raii thread-safety
我有一个线程类,我偶尔会从中获取一个指针实例变量.我希望这个访问由互斥锁保护,以便阻止线程访问此资源,直到客户端完成其指针.
我最初的方法是返回一对对象:一个是指向资源的指针,另一个是指向互斥锁上的锁定对象的shared_ptr.此shared_ptr包含对锁对象的唯一引用,因此当超出范围时,应该解锁互斥锁.像这样的东西:
void A::getResource()
{
Lock* lock = new Lock(&mMutex);
return pair<Resource*, shared_ptr<Lock> >(
&mResource,
shared_ptr<Lock>(lock));
}
Run Code Online (Sandbox Code Playgroud)
此解决方案不太理想,因为它要求客户端保留整个对象.这样的行为打破了线程的安全性:
Resource* r = a.getResource().first;
Run Code Online (Sandbox Code Playgroud)
另外,我自己实现的是死锁,我很难确定原因,所以可能还有其他问题.
我想要的是一个shared_ptr,它包含作为实例变量的锁,并将其与访问资源的方法绑定在一起.这似乎应该有一个既定的设计模式,但做了一些研究,我很惊讶地发现它很难找到.
我的问题是:
(注意我正在使用Qt的代码库,但遗憾的是在这种情况下不能使用boost.但是,涉及提升的答案仍然是普遍感兴趣的.)
我不确定是否有任何标准实现,但由于我喜欢无缘无故重新实现的东西,这里有一个应该工作的版本(假设你不想复制这样的指针):
template<class T>
class locking_ptr
{
public:
locking_ptr(T* ptr, mutex* lock)
: m_ptr(ptr)
, m_mutex(lock)
{
m_mutex->lock();
}
~locking_ptr()
{
if (m_mutex)
m_mutex->unlock();
}
locking_ptr(locking_ptr<T>&& ptr)
: m_ptr(ptr.m_ptr)
, m_mutex(ptr.m_mutex)
{
ptr.m_ptr = nullptr;
ptr.m_mutex = nullptr;
}
T* operator ->()
{
return m_ptr;
}
T const* operator ->() const
{
return m_ptr;
}
private:
// disallow copy/assignment
locking_ptr(locking_ptr<T> const& ptr)
{
}
locking_ptr& operator = (locking_ptr<T> const& ptr)
{
return *this;
}
T* m_ptr;
mutex* m_mutex; // whatever implementation you use
};
Run Code Online (Sandbox Code Playgroud)
您正在描述由Kevlin Henney在Executing Around Sequences中描述的EXECUTE AROUND POINTER模式的变体.
我有一个原型实现,exec_around.h但我无法保证它在所有情况下都能正常工作,因为它正在进行中.它包含一个函数mutex_around,该函数创建一个对象并将其包装在智能指针中,该指针在访问时锁定和解锁互斥锁.