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. 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.

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

Thread 1

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

Thread 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.

My question regarding atomic_load and atomic_store in VC11:

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? that way locks on different shared_ptr's won't contend with each other. Is there a reason this was not done?

EDIT: VS implementation of 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.

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

2 Answers

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. 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.

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. 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.

4

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. That is, it would make the most common uses slower in order to provide a minor speed increase in less common cases.

1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like