From the reference I know that std::shared_ptr<T>
itself is thread-safe, because the reference counting is typically implemented by some std::atomic
with std::memory_order_relaxed
.
However, I still don't know how std::shared_ptr
ensures thread-safe under concurrent increment and decrement of the reference counter.
I.e.,
Thread 1:
// destructing shared_ptr<T>
// rc.fetch_sub(1)
// Thread 1 got RC == 0 and *thought* that he is the last owner
// ** call T::~T()
Thread 2:
// concurrently copy that shared_ptr<T>
// rc.fetch_add(1)
// Thread 2 got RC == 1 and *thought* that the copied shared_ptr is valid
// dereference the shared_ptr
// ** accessing the destructed T !
This case, although race, is not impossible. Here is an example code (manually construct an extreme case).
std::shared_ptr<T> ptr;
int main()
{
std::thread t([&ptr] ()
{
ptr = std::make_shared<int>();
} // reference counting decrease here! Call ~T()
);
auto ptr2 = ptr; // reference counting increase here!
ptr2->some_function(); // access destructed object!
t.join();
}
My question is:
- How does C++ reference say about this case?
- Does
std::shared_ptr<T>
ensure thread-safe even under concurrent increment and decrement of the reference counter?