我正在开发一个内存数据库,我的系统需要大量std::atomic_int
对象,这些对象大致充当数据库记录的锁。现在我更愿意使用 VM 系统调用来分配这些锁,例如mmap
在类 Unix 系统和VirtualAlloc
Win32/64 上。这有几个原因,其中只有一个不需要显式初始化内存(即,由 VM 系统调用分配的内存保证由操作系统清零)。所以,我基本上想这样做:
#include <sys/mman.h>
#include <atomic>
// ...
size_t numberOfLocks = ... some large number ...;
std::atomic_int* locks = reinterpret_cast<std::atomic_int*>(mmap(0, numberOfLocks * sizeof(std::atomic_int), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0));
// ... use locks[i].load() or locks[i].store() as with any memory order as appropriate
我的主要问题是这段代码是否安全。我直观地期望代码可以在任何合理的平台上使用现代编译器工作:mmap
保证返回与 VM 页面边界对齐的内存,因此std::atomic_int
应该遵守任何对齐要求,并且构造函数std::atomic_int
不会初始化值所以有只要以合理的方式(例如,使用__atomic_*
GCC 和 clang 的内置函数)实现长时间的读取和写入,就没有不调用构造函数的危险。
但是,我可以想象,根据 C++ 标准,这段代码不一定是安全的——我这样想对吗?如果这是正确的,是否有任何检查,如果代码在目标平台上成功编译(即,如果实现std::atomic_int
是我期望的那样),那么一切都按我期望的那样工作?
与此相关,我希望以下代码(其中std::atomic_int
未对齐属性)在 x86 上中断:
uint8_t* region = reinterpret_cast<uint8_t*>(mmap(...));
std::atomic_int* lock = reinterpret_cast<std::atomic_int*>(region + 1);
lock->store(42, std::memory_order_relaxed);
我认为这不应该起作用的原因是因为在 x86 上合理实现std::atomic_int::store
withstd::memory_order_relaxed
只是一个正常的举动,它保证仅对字对齐访问是原子的。如果我对此是正确的,是否可以在代码中添加任何内容以防止此类情况发生并可能在编译时检测到此类问题?