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

新手上路,请多包涵

我有一个线程类,我想偶尔从中获取一个实例变量的指针。我希望这种访问受到互斥锁的保护,以便在客户端完成其指针之前阻止线程访问此资源。

我最初的方法是返回一对对象:一个是指向资源的指针,一个是指向互斥锁对象的 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。但是,涉及 boost 的答案仍然是普遍感兴趣的。)

原文由 Tim MB 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 507
1 个回答

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

 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
};

原文由 riv 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题