如何创建锁定和解锁互斥锁的智能指针?

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,它包含作为实例变量的锁,并将其与访问资源的方法绑定在一起.这似乎应该有一个既定的设计模式,但做了一些研究,我很惊讶地发现它很难找到.

我的问题是:

  • 这种模式有共同的实现吗?
  • 将mutex置于我忽略的shared_ptr中是否存在问题,以防止这种模式被广泛传播?
  • 是否有充分的理由不实现我自己的shared_ptr类来实现这种模式?

(注意我正在使用Qt的代码库,但遗憾的是在这种情况下不能使用boost.但是,涉及提升的答案仍然是普遍感兴趣的.)

riv*_*riv 7

我不确定是否有任何标准实现,但由于我喜欢无缘无故重新实现的东西,这里有一个应该工作的版本(假设你不想复制这样的指针):

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)

  • 即使考虑到可能的非主题讨论的危险,我也不想激发,但*"我通常避免使用标准库"* - 哎哟! (7认同)
  • 为什么要实现复制构造函数和复制赋值运算符?要么将它们设为私有**又要未实现**,要么在1998年停止生活并将其定义为已删除. (3认同)

Jon*_*ely 5

您正在描述由Kevlin Henney在Executing Around Sequences中描述的EXECUTE AROUND POINTER模式的变体.

我有一个原型实现,exec_around.h但我无法保证它在所有情况下都能正常工作,因为它正在进行中.它包含一个函数mutex_around,该函数创建一个对象并将其包装在智能指针中,该指针在访问时锁定和解锁互斥锁.