std::shared_ptr<int> int_ptr;
int main() {
int_ptr = std::make_shared<int>(1);
std::thread th{[&]() {
std::weak_ptr int_ptr_weak = int_ptr;
auto int_ptr_local = int_ptr_weak.lock();
if (int_ptr_local) {
cout << "Value in the shared_ptr is " << *int_ptr_local << endl;
}
});
int_ptr.reset(nullptr);
th.join();
return 0;
}
Is the code above thread safe? I read this answer About thread-safety of weak_ptr but just wanted to make sure that the above code is thread safe.
The reason I ask this is that if the code above is indeed thread safe, I cannot understand how the std::weak_ptr
and std::shared_ptr
interfaces make the following operation atomic expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
. It just seems to me that making two logical lines of code like above cannot be made synchronous without using some sort of mutex or spinlock.
I understand how atomic increments work with different instances of shared pointers and I understand that shared_ptr
s themselves are not thread safe, but if the above is indeed thread safe it is very much like a thread safe shared_ptr
and I don't understand how two lines of code like in the conditional above can be made atomic without locks.
A std::shared_ptr consists of a control block and its resource. The control block is thread-safe, but access to the resource is not. This means modifying the reference counter is an atomic operation and you have the guarantee that the resource is deleted exactly once.
The only difference between weak_ptr and shared_ptr is that the weak_ptr allows the reference counter object to be kept after the actual object was freed. As a result, if you keep a lot of shared_ptr in a std::set the actual objects will occupy a lot of memory if they are big enough.
The weak_ptr class template stores a "weak reference" to an object that's already managed by a shared_ptr. To access the object, a weak_ptr can be converted to a shared_ptr using the shared_ptr constructor or the member function lock.
Using weak_ptr and shared_ptr across threads is safe; the weak_ptr/shared_ptr objects themselves aren't thread-safe. You can't read/write to a single smart pointer across threads.
Is the code above thread safe?
I believe it's not, as int_ptr.reset(nullptr);
is racing against std::weak_ptr int_ptr_weak = int_ptr;
I cannot understand how the std::weak_ptr and std::shared_ptr interfaces make the following operation atomic
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
Such an operation is not atomic, as expired()
may return false, yet by the time you act upon that value, it may no longer be accurate. On the other hand if it returns true, that's guaranteed to remain accurate, as long as no one modified this particular instance of shared_ptr since then. That is, operations on other copies of a given shared_ptr can't cause it to unexpire.
The weak_ptr::lock()
implementation is not going to be using expired()
. It will probably do something like atomic compare-exchange, where an extra strong reference is added only if the current number of strong references is greater than zero.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With