简体   繁体   English

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

[英]atomic_load/atomic_store on std::shared_ptr in VC11 - why the global spinlock?

I'm trying to understand exactly how to manage shared pointers safely with atomic operations. 我试图准确理解如何使用原子操作安全地管理共享指针。 Turns out VC11 (Visual studio 2012) has support for C++11 and thereby can permit read/write races on std::shared_ptr. 原来VC11(Visual Studio 2012)支持C ++ 11,因此可以允许std :: shared_ptr上的读/写比赛。 I want to check I understood the basics, then ask something about the implementation detail of the atomic ops on std::shared_ptr in VC11. 我想检查我理解基础知识,然后在VC11中询问有关std :: shared_ptr上原子操作的实现细节。

std::shared_ptr<A> x, y, z;
x = std::make_shared<A>(args1);
y = std::make_shared<A>(args2);

Thread 1 线程1

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

Thread 2 线程2

std::atomic_store(&y, z);

Without the atomics, the race would potentially cause temp to end up having corrupted state, or Thread 2 could delete the A instance pointed to by the original y just as Thread 1 was attempting to copy and addref the shared_ptr, which would make it point to a "zombie" object. 如果没有原子,竞争可能会导致temp最终出现损坏状态,或者线程2可能会删除原始y指向的A实例,就像Thread 1尝试复制并添加sharedref一样,这会使它指向一个“僵尸”对象。

My question regarding atomic_load and atomic_store in VC11: 关于VC11中atomic_load和atomic_store的问题:

I've noticed they use a spinlock that performs test-and-set on a global variable. 我注意到他们使用了一个在全局变量上执行测试和设置的自旋锁。 So I wondered: why not do the test-and-set on the topmost bit of the reference counter of the shared_ptr itself? 所以我想知道:为什么不在shared_ptr本身的参考计数器的最高位进行测试和设置? that way locks on different shared_ptr's won't contend with each other. 这种方式锁定不同的shared_ptr将不会相互竞争。 Is there a reason this was not done? 有没有理由不这样做?

EDIT: VS implementation of atomic_is_lock_free . 编辑:VS的atomic_is_lock_free实现。 Not surprising, since it IS using a spinlock for everything. 这并不奇怪,因为它使用螺旋锁来应对一切。 Still wondering why they couldn't make it use a shared_ptr-instance-specific lock instead of a global lock. 仍然想知道为什么他们不能使用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);
}

You can't do an atomic test-and-set on the shared_ptr's ref count because the ref count is stored in the shared_ptr's control block. 您不能对shared_ptr的引用计数进行原子测试和设置,因为引用计数存储在shared_ptr的控制块中。 By the time you got around to attempting your test-and-set, another thread could have released the last shared_ptr reference and deleted the control block from under you. 当你开始尝试测试和设置时,另一个线程可能已经释放了最后一个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)

Remember that the premise here is that multiple threads are manipulating the same shared_ptr instance. 请记住,这里的前提是多个线程正在操作同一个 shared_ptr实例。 If each thread has its own instance (pointing to the same controlled object), then we have no issues and no need for atomic shared_ptr operations. 如果每个线程都有自己的实例(指向同一个受控对象),那么我们没有问题,也不需要原子shared_ptr操作。

Munging the top bit of the reference count would require code that deals with the reference count as a counter to ignore that top bit. Munging引用计数的最高位将需要处理引用计数的代码作为忽略该顶部位的计数器。 That is, it would make the most common uses slower in order to provide a minor speed increase in less common cases. 也就是说,它会使最常见的用途变慢,以便在不太常见的情况下提供较小的速度增加。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM