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
对象数组。我可以想出两种解决办法:
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>;
}