Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is shared_ptr destruction safe with multiple threads?

I have two classes similar to this:

class Foo {
 public:
  void bar() {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_data.push_back('x');
  }
 private:
  std::string m_data;
  std::mutex m_mutex;
};

class Pool {
 public:
   static std::shared_ptr<Foo> Create(int index) {
     std::lock_guard<std::mutex> lock(m_mutex);
     if (m_pool.size() > 10) {
       m_pool.erase(m_pool.begin());
     }
     std::shared_ptr<Foo>& ptr = m_pool[index];
     if (!ptr) ptr.reset(new Foo);
     return ptr;
   }
 private:
   static std::mutex m_mutex;
   static std::map<int, std::shared_ptr<Foo>> m_pool;
};

and several threads running this code:

void parallel_function(int index) {
  // several threads can get the same index
  std::shared_ptr<Foo> foo = Pool::Create(index);
  foo->bar();
}

Cppreference says

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.

Two questions:

  1. Since Pool::Create always returns copies of the shared_ptr, I assume that the copy and destruction of each shared_ptr is thread-safe, either if it happens in m_pool.erase or at the end of parallel_function. Is this correct?

  2. I call shared_ptr::operator->, which is a const member function, and the function Foo::bar is thread-safe. Is there a data race here?

like image 927
ChronoTrigger Avatar asked Sep 27 '22 15:09

ChronoTrigger


1 Answers

To sum up my comments.

  1. Yes, this is thread safe as you operate separate copies of shared_ptrs in different threads. Which is one of the few cases where passing copies of shared_ptrs is actually reasonable.
  2. operator-> is a const member. So basically your code is fine as long as Foo::bar being race-free stands true (which it clearly is now).
like image 172
Rostislav Avatar answered Nov 05 '22 08:11

Rostislav