std :: weak_ptr <t> :: lock线程安全吗?

时间:2018-07-28 02:22:28

标签: c++ multithreading weak-ptr c++20

下面是一些示例代码,显示了我的用例。我有一个PIMPL,可以共享实现(只是一堆昂贵的数据),但是当不再需要该实现时,可以销毁该实现。类HasImpl的实例使用指向Impl的共享指针,并且该类定义包括static weak_ptrImpl,它们充当的新实例的“指针分配器” HasImpl,为他们提供Impl的句柄。

该示例有两种调用weak_ptr::lock的方法-一种假定对以下问题1-3的回答均为“是”,而另一种则不是。我更喜欢weak_ptr::lock是线程安全的唯一原因是,可能有多个线程试图获取指向Impl的指针的副本,并且如果lock是线程安全的,大多数执行线程将不必传递静态变量定义(该线程将必须检查该线程是否已初始化),也不必竞争获取互斥体。

/* In HasImpl.h */
class HasImpl {
public:
  HasImpl();
private:
  class Impl;
  static std::weak_ptr<Impl> sharedImplDispenser;
  std::shared_ptr<Impl> myPtrToSharedImpl;
}

/* In HasImpl.cpp */
class HasImpl::Impl {
public:
  Impl(); //constructor that takes a lot of time to run
  //Lots of stuff, expensively produced, accessable to HasImpl through a shared_ptr to Impl
}

/* hypothetical constructor if weak_ptr::lock is thread-safe */
HasImpl::HasImpl() : myPtrToSharedImpl{sharedImplDispenser.lock()}
{
  if (!myPtrToSharedImpl) {
    static std::mutex mtx;
    std::lockguard<std::mutex> lck(mtx);
    myPtrToSharedImpl = sharedImplDispenser.lock();
    if (!myPtrToSharedImpl) {
      const auto new_impl{std::make_shared<Impl()};
      sharedImplDispenser = new_impl; // the only place in the program where a value is assigned to sharedImplDispenser
      myPtrToSharedImpl = new_impl;
    }
  }
}

/* hypothetical constructor if weak_ptr::lock is not thread-safe */
HasImpl::HasImpl()
{
  static std::mutex mtx;
  std::lockguard<std::mutex> lck(mtx);
  myPtrToSharedImpl = sharedImpl.lock();
  if (!myPtrToSharedImpl) {
    const auto new_impl{std::make_shared<Impl()};
    sharedImplDispenser = new_impl; // the only place in the program where a value is assigned to sharedImplDispenser
    myPtrToSharedImpl = new_impl;
  }
} 
  1. 假设std::weak_ptr不为空并且在遥远的某个时候被分配了一个指针,如果一个线程调用weak_ptr::lock而另一个线程正在调用weak_ptr::lock,则控制块可以正常运行?
  2. 是否正在调用weak_ptr::lock,而另一个线程可能正在将ptr分配给足够安全的空weak_ptr?也就是说,该值将返回nullptr还是新指针?我不在乎nullptr是否是伪造的(也就是说,该分配已经发生,但其他线程还不知道)。我只是不想破坏控制块或从调用中获取无效的指针值。
  3. 正在销毁对象的最后一个shared_ptr时调用weak_ptr::lock吗?
  4. 如果1到3有问题,C ++ 20中的std::atomic<std::weak_ptr<T>>是否可以解决问题?

1 个答案:

答案 0 :(得分:5)

该标准明确指出weak_ptr::lock是“原子执行的”。这样就可以回答1和3。

对于#2,如果您要分配给相同 weak_ptr,那是一场数据竞赛。更改共享状态use_count的操作不会引起数据争用,但是复制或操纵weak_ptr本身并不只是在use_count上戳。

但是,如果您要谈论的是锁定一个weak_ptr,同时使正在讨论相同共享状态的另一个weak_ptr无效,那很好。两者仅通过共享状态的计数进行交互,这很好。

是的,atomic<weak_ptr<T>>将允许您从多个线程中操作同一对象。