原子int集合的线程安全性

时间:2015-09-08 15:40:12

标签: c++ multithreading c++11 stdatomic

我有以下类包装原子整数的向量(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 );
    }
};

我怀疑这可能不是线程安全的(它目前在没有问题的单线程模型中运行),但会欣赏任何观点。我主要担心的是无人看守的集合的线程安全性,而不是它的元素。

1 个答案:

答案 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 );
    }
};