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

时间:2013-03-09 11:22:09

标签: c++ visual-studio-2012 shared-ptr atomic

我正在努力了解如何使用原子操作安全地管理共享指针。原来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);

线程1

std::shared_ptr<A> temp = std::atomic_load(y);

线程2

std::atomic_store(&y, z);

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

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

我注意到他们使用了一个在全局变量上执行测试和设置的自旋锁。 所以我想知道:为什么不在shared_ptr本身的参考计数器的最高位进行测试和设置?这种方式锁定不同的shared_ptr将不会相互竞争。有没有理由不这样做?

编辑:VS atomic_is_lock_free的实施。这并不奇怪,因为它使用螺旋锁来应对一切。仍然想知道为什么他们不能使用shared_ptr-instance特定的锁而不是全局锁。

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

2 个答案:

答案 0 :(得分:2)

您无法对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)

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

答案 1 :(得分:0)

引用引用计数的最高位将需要处理引用计数的代码作为忽略该最高位的计数器。也就是说,它会使最常见的用途变慢,以便在不太常见的情况下提供较小的速度增加。