获取/释放通过[] -operator访问的原子变量的语义

mor*_*ort 6 c++ arrays shared-memory c++11

假设一个原子变量数组和一个类,它通过重载类' []-operator来返回对该位置的原子变量的引用来调节对该数组的访问idx:

class MyClass {
public:
    MyClass()
    {
        //initalize every array element with nullptr
        for (auto& it : array) {
            it = nullptr;
        }
    }
    std::atomic<int*>& operator[](const size_t idx)
    {
         //there is some more code here, doing basic safety checks,...
         return array[idx];
    }
private:
    std::array<std::atomic<int*>, 1000> array;

}
Run Code Online (Sandbox Code Playgroud)

我们可以访问这样的元素array:

MyClass foo();
int *a = foo[0];
int b = 3;
foo[1] = &b
Run Code Online (Sandbox Code Playgroud)

请注意,默认情况下,对此类元素的任何访问都将使用memory_order_seq_cst.要更改强制内存顺序,可以执行以下操作:

int *a = foo[0].load(memory_order_acquire);
foo[1].store(&b, memory_order_release);
Run Code Online (Sandbox Code Playgroud)

但是,如何更改[]-operator的实现,以便memory_order_acquire用于所有读取并memory_order_release用于所有写入?我想在[]-operator 的定义中执行此操作的原因是,array在源中的许多不同位置存在大量访问元素,并且我不希望将使用的内存排序分散到所有这些元素中.

编辑:正如评论中所讨论的,可以用[]getter和setter 替换-operator.但是,这将要求所有访问都被适当的函数替换; 加上我是否有可能按照上面概述的方式进行操作.

jxh*_*jxh 4

您可以使用作为operator[]. 然后,该对象根据该对象在未来表达式中的使用方式来应用加载或存储操作。

class MyClass {
    struct Ref {
        std::atomic<int *> &ref_;
        Ref (std::atomic<int *> &r) : ref_(r) {}
        operator int * () const {
            return ref_.load(std::memory_order_acquire);
        }
        int * operator = (int *ptr) const {
            ref_.store(ptr, std::memory_order_release);
            return ptr;
        }
    };
public:
    //...
    Ref operator[](const size_t idx)
    {
         //there is some more code here, doing basic safety checks,...
         return array[idx];
    }
    //...
};
Run Code Online (Sandbox Code Playgroud)

然后,转换运算符或赋值运算符将使用正确的内存顺序约束:

MyClass foo;
int *a = foo[0];  // uses conversion operator, load(acquire)
int b = 3;
foo[1] = &b;      // uses assignment operator, store(release)
Run Code Online (Sandbox Code Playgroud)