是std :: weak_ptr <T> ::锁线程安全吗?

rsj*_*ffe 1 c++ multithreading weak-ptr c++20

下面是一些显示我的用例的示例代码.我有一个PIMPL,可以共享实现(它只是一堆昂贵的数据),但实现可以在不再需要时销毁.类的一个实例HasImpl使用一个共享指针Impl,类定义包括一个static weak_ptrto Impl作为新指针的"指针分配器" 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;
  }
} 
Run Code Online (Sandbox Code Playgroud)
  1. 假设它std::weak_ptr不是空的并且在遥远的过去某个时间被分配了一个指针,如果一个线程调用weak_ptr::lock而另一个线程可能正在调用,那么控制块是否正常weak_ptr::lock
  2. 正在调用weak_ptr::lock而另一个线程可能正在将一个ptr分配给空的weak_ptr足够安全吗?也就是说,该值是返回nullptr还是新指针?我不在乎nullptr是否是假的(也就是说,已经发生了这种分配但其他线程还不知道它).我只是不想破坏控制块或从调用中获取无效的指针值.
  3. 正在调用weak_ptr::lock对象的最后一个shared_ptr被破坏线程安全吗?
  4. 如果1到3出现问题,std::atomic<std::weak_ptr<T>>C++ 20会解决这个问题吗?

Nic*_*las 5

该标准明确表示weak_ptr::lock"以原子方式执行".所以答案1和3.

#2,如果你问有关分配到相同的 weak_ptr,那么它是一个数据的比赛.改变共享状态的use_count操作不会引发数据争用,但复制或操纵weak_ptr本身不仅仅是在捅东西use_count.

但是,如果你正在谈论锁定一个weak_ptr同时将另一个同时weak_ptr处理同一共享状态的另一个解锁,那就没问题.这两个只通过共享状态的计数进行交互,这被认为是好的.

是的,atomic<weak_ptr<T>>允许您从多个线程操纵同一个对象.