1

I was reading about thread safety of std::shared_ptr and about the atomic operations overloads it provides and was wondering regarding a specific use case of it in a class.

From my understanding of the thread safety that is promised from shared_ptr, it is safe to have a get method like so:

class MyClass 
{
std::shared_ptr<int> _obj;
public:
    void start() 
    {
        std::lock_guard<std::mutex> lock(_mtx);
        _obj = std::make_shared<int>(1);
    }

    void stop()
    {
          std::lock_guard<std::mutex> lock(_mtx);
        _obj.reset();

    }
    std::shared_ptr<int> get_obj() const
    {
        return _obj; //Safe (?)
    }
};

The getter should be safe since the object will either be initializes or empty at any point from any thread.

But what if I want to throw an exception if the object is empty, I need to check it before returning it, do I have to put a lock there now (since stop() might be called between the if and the return)? Or is it possible to use the locking mechanism of the shared pointer and not use a lock in this method:

   std::shared_ptr<int> get_obj() const
    {
        auto tmp = _obj;
        if(!tmp) throw std::exception();
        return tmp;
    }
2
  • 2
    get_obj races with start and stop. Something needs to additionally guarantee that the former doesn't get call concurrently with the latter. The second version has the same data race as the first - no better and no worse. Commented Jan 13, 2019 at 17:57
  • See also stackoverflow.com/questions/20705304/…. Not an exact duplicate, but the answers are relevant to your question. Commented Apr 23, 2020 at 17:53

1 Answer 1

4

std::shared_ptr instances are not thread safe. Multiple instances all pointing to the same object can be modified from multiple threads but a single instance is not thread safe. See https://en.cppreference.com/w/cpp/memory/shared_ptr:

All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of atomic functions can be used to prevent the data race.

You therefore either need to lock your mutex in your get_obj method or use std::atomic_load and std::atomic_store in your start and stop methods

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.