VC11 中 std::shared_ptr 上的atomic_load/atomic_store - 为什么全局自旋锁?

yon*_*nil 7 c++ atomic shared-ptr visual-c++ visual-studio-2012

我试图准确理解如何通过原子操作安全地管理共享指针。事实证明 VC11 (Visual studio 2012) 支持 C++11,因此可以允许 std::shared_ptr 上的读/写竞争。我想检查一下我是否理解了基础知识,然后询问有关 VC11 中 std::shared_ptr 上原子操作的实现细节。

std::shared_ptr<A> x, y, z;
x = std::make_shared<A>(args1);
y = std::make_shared<A>(args2);
Run Code Online (Sandbox Code Playgroud)

线程1

std::shared_ptr<A> temp = std::atomic_load(&y);
Run Code Online (Sandbox Code Playgroud)

线程2

std::atomic_store(&y, z);
Run Code Online (Sandbox Code Playgroud)

如果没有原子,竞争可能会导致temp最终状态损坏,或者线程 2 可能会删除原始 y 所指向的 A 实例,就像线程 1 试图复制并添加共享指针一样,这将使其指向一个“僵尸”对象。

我关于VC11中atomic_load和atomic_store的问题:

我注意到他们使用自旋锁来对全局变量执行测试和设置。所以我想知道:为什么不在shared_ptr本身的引用计数器的最高位上进行测试和设置?这样不同的shared_ptr上的锁就不会相互竞争。没有这样做有什么原因吗?

编辑: VS 的实现atomic_is_lock_free。这并不奇怪,因为它对所有事情都使用自旋锁。仍然想知道为什么他们不能让它使用共享指针实例特定的锁而不是全局锁。

template <class _Ty> inline
bool atomic_is_lock_free(const shared_ptr<_Ty> *)
{   // return true if atomic operations on shared_ptr<_Ty> are lock-free
    return (false);
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*man 5

您无法对shared_ptr的引用计数进行原子测试和设置,因为引用计数存储在shared_ptr的控制块中。当您开始尝试测试和设置时,另一个线程可能已经释放了最后一个shared_ptr引用并删除了您下面的控制块。

Thread 1                                  Thread 2
Read control block address

                                          Decrement ref count (now 0)
                                          Delete control block

Test-and-set ref count (undefined behaviour)
Run Code Online (Sandbox Code Playgroud)

请记住,这里的前提是多个线程正在操作同一个shared_ptr实例。如果每个线程都有自己的实例(指向同一个受控对象),那么我们就没有问题,也不需要原子的shared_ptr操作。

  • 我很清楚,里奥基。我认为你没有抓住重点。最初的问题是关于atomic_shared_ptr 的潜在实现。我在这里试图解释的是为什么即使使用原子加载和存储,该实现也不起作用。 (2认同)