nhtrnm
nhtrnm

Reputation: 1617

Atomic operations on shared_ptr

Assume I have shared_ptr<T> a and two threads running concurrently where one does:

a.reset();

and another does:

auto b = a;

if the operations are atomic, then I either end up with two empty shared_ptrs or a being empty and b pointing to what was pointed to by a. I am fine with either outcome, however, due to the interleaving of the instructions, these operations might not be atomic. Is there any way I can assure that?

To be more precise I only need a.reset() to be atomic.

UPD: as pointed out in the comments my question is silly if I don't get more specific. It is possible to achieve atomicity with a mutex. However, I wonder if, on the implementation level of shared_ptr, things are already taken care of. From cppreference.com, copy assignment and copy constructors are thread-safe. So auto b = a is alright to run without a lock. However, from this it's unclear if a.reset() is also thread-safe.

UPD1: it would be great if there is some document that specifies which methods of shared_ptr are thread-safe. From cppreference:

If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur

It is unclear to me which of the methods are non-const.

Upvotes: 1

Views: 2251

Answers (2)

Brian Bi
Brian Bi

Reputation: 119164

std::shared_ptr<T> is what some call a "thread-compatible" class, meaning that as long as each instance of a std::shared_ptr<T> can only have one thread calling its member functions at a given point in time, such member function invocations do not cause race conditions, even if multiple threads are accessing shared_ptrs that share ownership with each other.

std::shared_ptr<T> is not a thread-safe class; it is not safe for one thread to call a non-const method of an std::shared_ptr<T> instance while another thread is also accessing the same instance. If you need potentially concurrent reads and writes to not race, then synchronize them using a mutex.

Upvotes: 2

selbie
selbie

Reputation: 104514

Let the other thread use a weak_ptr. The lock() operation on weak pointer is documented to be atomic.

Create:

std::shared_ptr<A> a = std::make_shared<A>();
std::weak_ptr<A> a_weak = std::weak_ptr<A>(a);

Thread 1:

a.reset();

Thread 2:

b = a_weak.get();
if (b != nullptr)
{
    ...
}

Upvotes: 3

Related Questions