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:
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?
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?
To sum up my comments.
shared_ptr
s in different threads. Which is one of the few cases where passing copies of shared_ptr
s is actually reasonable.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).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