1

我有以下类包装了一个原子整数向量(std::vector< std::atomic_int >

向量在对象构造时的大小是正确的,并且不会改变大小。有用于获取、设置原子整数的常用访问器和修改器,但没有警卫/互斥锁。

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

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

4

1 回答 1

3

首先,重要的是要注意,如果没有一些恶作剧,就不能拥有原子整数向量。

忽略这一点,根据 [container.requirements.dataraces] 如果您只访问向量来修改其内容,那么这似乎是线程安全的。

为了避免数据竞争 (17.6.5.9),实现应将以下函数视为 const:begin、end、rbegin、rend、front、back、data、find、lower_bound、upper_bound、equal_range、at 和,但在关联中除外或无序的关联容器,operator[]。

尽管有(17.6.5.9),当同时修改同一容器中不同元素中包含的对象的内容时,需要实现以避免数据竞争,除了vector<bool>。

operator[]关于在这种情况下是否可能是非线程安全的措辞不是很清楚,但实际上任何合理的实现都不应该违反这一点。

如果你想要更多的保证,并且由于向量不会改变大小,你可以vector<T>用 a替换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 );
    }
};
于 2015-09-08T15:54:42.807 回答