As it's well known that shared_ptr
only guarantees access to underlying control block is thread
safe and no guarantee made for accesses to owned object.
Then why there is a race condition in the code snippet below:
std::shared_ptr<int> g_s = std::make_shared<int>(1);
void f1()
{
std::shared_ptr<int>l_s1 = g_s; // read g_s
}
void f2()
{
std::shared_ptr<int> l_s2 = std::make_shared<int>(3);
std::thread th(f1);
th.detach();
g_s = l_s2; // write g_s
}
In the code snippet above, the owned object of the shared pointer named g_s
are not accessed indeed.
I am really confused now. Could somebody shed some light on this matter?
CodePudding user response:
std::shared_ptr<T>
guarantees that access to its control block is thread-safe, but not access to the std::shared_ptr<T>
instance itself, which is generally an object with two data members: the raw pointer (the one returned by get()
) and the pointer to the control block.
In your code, the same std::shared_ptr<int>
instance may be concurrently accessed by the two threads; f1
reads, and f2
writes.
If the two threads were accessing two different shared_ptr
instances that shared ownership of the same object, there would be no data race. The two instances would have the same control block, but accesses to the control block would be appropriately synchronized by the library implementation.
If you need concurrent, race-free access to a single std::shared_ptr<T>
instance from multiple threads, you can use std::atomic<std::shared_ptr<T>>
. (There is also an older interface that can be used prior to C 20, which is deprecated in C 20.)