我有以下类包装原子整数的向量(std::vector< std::atomic_int >
)
矢量在对象构造时的大小正确,并且不会改变大小。有通常的访问器和mutator用于获取,设置原子int,但没有guards / mutex。
class MyList
{
std::vector< std::atomic_int > collection_;
static MyList myList_;
public:
MyList() : collection_( MAX_SIZE, 0 ) {}
static MyList& getMyList() { return myList_; }
void set( size_t idx, int val )
{
collection_[idx].store( val, std::memory_order_relaxed );
}
int get( size_t idx ) const
{
return collection_[idx].load( std::memory_order_relaxed );
}
};
我怀疑这可能不是线程安全的(它目前在没有问题的单线程模型中运行),但会欣赏任何观点。我主要担心的是无人看守的集合的线程安全性,而不是它的元素。
答案 0 :(得分:3)
首先,重要的是要注意你can't have a vector of atomic ints没有一些恶作剧。
忽略这一点,根据[container.requirements.dataraces],如果你只访问向量来修改其内容,那么这似乎是线程安全的。
为了避免数据竞争(17.6.5.9),实现应考虑以下函数 const:begin,end,rbegin,rend,front,back,data,find,lower_bound,upper_bound,equal_range,at 并且,除了在关联或无序的关联容器中,运算符[]。
尽管如此(17.6.5.9),当实现内容时,需要实现以避免数据争用 除了向量&lt; bool&gt;之外,同一容器中不同元素中的对象被同时修改。
在这种情况下,operator[]
是否可能是非线程安全的措辞不是很清楚,但实际上没有合理的实施可能违反这一点。
如果您需要更多保证,并且由于矢量不会改变大小,您可以将vector<T>
替换为unique_ptr<T[]>
,在这种情况下,这通常是线程安全的。
此外,您应该使用保证安全同步和排序的内存顺序(除非您有充分的理由),而不是memory_order_relaxed
。根本不指定内存订单,或使用memory_order_acquire
/ memory_order_release
对执行此操作
这导致以下非常相似的代码:
class MyList
{
std::unique_ptr< std::atomic_int[] > collection_;
static MyList myList_;
public:
MyList() : collection_( new atomic_int[MAX_SIZE] ) {}
static MyList& getMyList() { return myList_; }
void set( size_t idx, int val )
{
collection_[idx].store( val, std::memory_order_release );
}
int get( size_t idx ) const
{
return collection_[idx].load( std::memory_order_acquire );
}
};