Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How `weak_ptr` and `shared_ptr` accesses are atomic

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_ptrs 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.

like image 704
Curious Avatar asked Jan 06 '17 06:01

Curious


People also ask

Is shared_ptr Atomic?

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.

What is the difference between shared_ptr and weak_ptr?

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.

How can a weak_ptr be turned into a shared_ptr?

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.

Is weak_ptr lock thread safe?

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.


1 Answers

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.

like image 109
Joseph Artsimovich Avatar answered Nov 15 '22 05:11

Joseph Artsimovich