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.
This question has two parts:
Thread-safety
The code is NOT threadsafe, but this has nothing to do with
lock()
:The race exists between
int_ptr.reset();
andstd::weak_ptr int_ptr_weak = int_ptr;
. Because one thread is modifying the non-atomic variableint_ptr
while the other reads it, which is - by definition - a data race.So this would be OK:
Atomic version of the example code
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
Of course the whole process can't be atomic. The actually important part is that the strong ref count is only incremented if it is already greater than zero and that the check and the increment happen in an atomic fashion. I don't know if there are any system/architecture specific primitives available for this, but one way to implement it in c++11 would be: