Я разрабатываю базу данных в памяти, и моей системе нужен большой массив std::atomic_int
объектов, которые примерно действуют как блокировки для записей базы данных.Теперь я бы предпочел распределить эти блокировки с помощью системных вызовов VM, таких как mmap
в Unix-подобных системах и VirtualAlloc
в Win32 / 64.Для этого есть несколько причин, и только одна из них не нуждается в явной инициализации памяти (т. Е. Память, выделенная системными вызовами ВМ, гарантированно обнуляется ОС).Итак, я бы хотел сделать это:
#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
гарантированно вернет память, выровненную по границе страницы виртуальной машины, поэтому должны соблюдаться все требования выравнивания 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);
Причина, по которой я думаю, что это не должно работать, заключается в том, что разумная реализацияstd::atomic_int::store
с std::memory_order_relaxed
на x86 - это просто нормальное движение, которое гарантированно будет атомарным только для доступа с выравниванием по словам.Если я прав в этом, могу ли я что-нибудь добавить в код, чтобы защитить от таких ситуаций и, возможно, обнаружить такие проблемы во время компиляции?