C++ 在C+中以原子方式访问内存块的部分(例如字符数组)+;

C++ 在C+中以原子方式访问内存块的部分(例如字符数组)+;,c++,multithreading,c++11,atomic,strict-aliasing,C++,Multithreading,C++11,Atomic,Strict Aliasing,我的用例 我有一个管理大量数据记录的程序,每个记录的大小为R字节。每个记录都有一个大小为4字节的锁。因此,每个记录总共占用S=R+4字节。由于特定于应用程序的原因,这些记录必须相邻放置在内存中,如下所示: -------------------------------------------------------------------------------------------. |锁定| 1|数据| 1|锁定| 2|数据| 2锁定数据 -------------------------

我的用例

我有一个管理大量数据记录的程序,每个记录的大小为
R
字节。每个记录都有一个大小为4字节的锁。因此,每个记录总共占用
S=R+4
字节。由于特定于应用程序的原因,这些记录必须相邻放置在内存中,如下所示:

-------------------------------------------------------------------------------------------.
|锁定| 1|数据| 1|锁定| 2|数据| 2锁定数据
-----------------------------------------------------------------------------------------。

请注意,
R
在编译时是未知的,因此我不能使用以下方法静态分配记录:

struct S {
   std::atomic<int> lock;
   char data[R];
} region[N];

问题

如何使用
std::atomic
函数以原子方式修改锁,而不必实际维护
std::atomic
对象数组。我可以想出两种解决办法:

  • 如果Linux内核对
    int
    std::atomic
    使用相同的位表示,并且
    char*
    是严格别名规则的例外,即允许它指向任何类型,那么抛出char类型的指针(它指的是锁)安全吗到
    std::atomic
    ,例如:

    char* x = region + (lockID * S);
    reinterpret_cast<atomic<int>*>(x)->fetch_add(1);
    
    在这里,出于空间考虑,我不想保留一个
    lockPtr
    s数组,因此我将它们扔掉,并使用解决方案1的强制转换来获取指向给定锁的原子对象的指针


  • 这些解决方案中有任何一种是正确的吗?如果不是,正确的解决方案是什么?

    重新解释的版本是未定义的行为。新版本的布局看起来还可以,但不确定对齐要求。1。不正确,并破坏严格的别名规则。2.可能没问题,
    std::launder
    可能有用。如果您的记录保证长度为4位的倍数,一个选项是将其转出到C函数,其中别名规则允许使用原子int和char的并集[4]。C11别名规则更适合这种精确的内存布局问题。@RichardCriten不是严格别名规则的例外,因为它可以指向任何类型?那么从
    char*
    指针强制转换到
    std::atomic*
    指针不是很安全吗?定义了将任何指针强制转换到
    char*
    。只有当
    char*
    最初是从指向同一类型的指针(例如
    my\u-type*
    char*
    返回到
    my\u-type*
    时,才定义从
    char*
    到指向另一类型的指针的强制转换。新版本的布局看起来还可以,但不确定对齐要求。1。不正确,并破坏严格的别名规则。2.可能没问题,
    std::launder
    可能有用。如果您的记录保证长度为4位的倍数,一个选项是将其转出到C函数,其中别名规则允许使用原子int和char的并集[4]。C11别名规则更适合这种精确的内存布局问题。@RichardCriten不是严格别名规则的例外,因为它可以指向任何类型?那么从
    char*
    指针强制转换到
    std::atomic*
    指针不是很安全吗?定义了将任何指针强制转换到
    char*
    。只有当
    char*
    最初是从指向同一类型的指针(例如
    my\u type*
    char*
    返回到
    my\u type*
    时,才定义从
    char*
    到指向另一类型的指针的强制转换
    char* x = region + (lockID * S);
    reinterpret_cast<atomic<int>*>(x)->fetch_add(1);
    
    for (int lockID = 0; lockID < N; lockID++) {
         char* memoryOffset = region + (lockID * S);
         std::atomic<int>* lockPtr = new (memoryOffset) std::atomic<int>; 
    }