我有一个带螺纹的类从中我想偶尔获得的指针的一个实例变量。 我想这个访问由互斥看守,使线从直到客户端与它的指针完成访问该资源的封锁。
我对这个初始的方法是一对对象返回:一个指针一个shared_ptr的资源之一的锁定对象互斥。 此shared_ptr的保持于锁定对象的唯一引用,以便当它超出范围的互斥应该被解锁。 事情是这样的:
void A::getResource()
{
Lock* lock = new Lock(&mMutex);
return pair<Resource*, shared_ptr<Lock> >(
&mResource,
shared_ptr<Lock>(lock));
}
这个解决方案是不理想的,因为它需要在客户端保持到整个对象对。 这样的行为打破了线程安全性:
Resource* r = a.getResource().first;
另外,我自己的实现的,这是死锁,我难以决定的原因,所以有可能是其他的东西错。
我想有是一个包含锁定为一个实例变量,以访问该资源的手段结合它一个shared_ptr。 这似乎喜欢的事,应该有一个既定的设计模式,不过话说做了一些研究,我很惊讶地发现它非常难遇到。
我的问题是:
- 是否有这种模式的一个常见的实现?
- 是否有与把一个互斥是我俯瞰,以防止这种模式被广泛的一个shared_ptr里面的问题?
- 是否有一个很好的理由不实现自己的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
};
你描述的变化进行以指针模式,通过凯夫林·海尼在描述执行大约序列 。
我曾在某原型实现exec_around.h
,但我不能保证它正常工作在所有情况下,因为它的工作正在进行中。 它包括一个功能mutex_around
它创建一个对象,并把它包装在智能指针锁和被访问时解锁互斥。
这里有另一种方法。 远不如灵活而且不通用,也简单得多。 虽然它似乎仍然满足您的实际情况。
shared_ptr
(包括标准和加速 )提供手段来构建它同时提供另一个shared_ptr
实例,该实例将用于使用计数器并不会在所有被管理的一些任意的指针。 在cppreference.com它是第八形式( 混叠构造函数 )。
现在,通常,这种形式用于转化-像提供shared_ptr
从派生类对象的基类对象。 他们分享的所有权和使用计数器,但(一般)有不同类型的两个不同的指针值。 这种形式也可以用来提供一个shared_ptr
基于成员值shared_ptr
到对象,它是一个成员。
在这里,我们可以“滥用”的形式提供锁定挡板。 像这样做:
auto A::getResource()
{
auto counter = std::make_shared<Lock>(&mMutex);
std::shared_ptr<Resource> result{ counter, &mResource };
return result;
}
返回shared_ptr
点mResource
并保持mMutex
锁定,只要它由任何人。
这种解决方案的问题是,它现在是你的责任,以确保mResource
仍然有效(特别是-它不会破坏)那么久也。 如果锁定mMutex
是足够的,那么你的罚款。
否则,上述解决方案必须进行调整,以您的特定需求。 例如,你可能希望有counter
的简单struct
,保持双方的Lock
,另一个shared_ptr
到A
对象拥有的mResource
。