我试图确切地了解如何通过原子操作安全地管理共享指针。事实证明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的对象就不会相互竞争。有没有这样做的原因吗?
编辑:
atomic_is_lock_free
的VS实现。不足为奇,因为它对所有内容都使用自旋锁。仍然想知道为什么他们不能使用shared_ptr-instance-specific锁而不是全局锁。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);
}
最佳答案
您不能对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操作。