我有两个类似的类:
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;
};
以及运行此代码的几个线程:
void parallel_function(int index) {
// several threads can get the same index
std::shared_ptr<Foo> foo = Pool::Create(index);
foo->bar();
}
所有成员函数(包括复制构造函数和复制赋值)都可以由shared_ptr的不同实例上的多个线程调用,而无需其他同步,即使这些实例是副本并共享同一对象的所有权。如果多个执行线程在没有同步的情况下访问相同的shared_ptr,并且这些访问中的任何一个使用shared_ptr的非const成员函数,那么将发生数据争用;原子函数的shared_ptr重载可用于防止数据竞争。
两个问题:
由于Pool::Create
总是返回shared_ptr
的副本,我假设每个shared_ptr
的复制和销毁都是线程安全的,如果它发生在{{1}中}或在m_pool.erase
的末尾。这是对的吗?
我调用parallel_function
这是一个const成员函数,函数shared_ptr::operator->
是线程安全的。这里有数据竞争吗?
答案 0 :(得分:3)
总结我的评论。
shared_ptr
的单独副本。这是传递shared_ptr
s副本实际上是合理的少数情况之一。operator->
是const member。所以基本上你的代码很好,只要Foo :: bar无竞争就行(现在很明显)。