У меня есть что-то вроде:
if (f = acquire_load() == ) {
... use Foo
}
и
auto f = new Foo();
release_store(f)
Вы легко можете представить себе реализацию gets_load и release_store, которая использует атомарную нагрузку (memory_order_acquire) и сохраняет (memory_order_release). Но что теперь, если release_store реализуется с _mm_stream_si64, невременной записью, которая не упорядочена по отношению к другим магазинам на x64? Как получить ту же семантику?
Я думаю, что требуется минимум:
atomic<Foo*> gFoo;
Foo* acquire_load() {
return gFoo.load(memory_order_relaxed);
}
void release_store(Foo* f) {
_mm_stream_si64(*(Foo**)&gFoo, f);
}
И используйте его так:
// thread 1
if (f = acquire_load() == ) {
_mm_lfence();
... use Foo
}
и
// thread 2
auto f = new Foo();
_mm_sfence(); // ensures Foo is constructed by the time f is published to gFoo
release_store(f)
Это правильно? Я почти уверен, что это абсолютно необходимо здесь. Но как насчет силы? Требуется ли или достаточно простого компилятора для x64? например asm volatile ( ":" memory"). Согласно модели памяти x86, нагрузки не переупорядочиваются с другими нагрузками. Поэтому, насколько мне известно, функция load_load() должна выполняться перед любой загрузкой внутри оператора if, если существует компилятор.