Может ли аппаратное обеспечение переупорядочить атомарную загрузку, за которой следует атомарное хранилище, если сохранеC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Может ли аппаратное обеспечение переупорядочить атомарную загрузку, за которой следует атомарное хранилище, если сохране

Сообщение Anonymous »

Может ли аппаратное обеспечение переупорядочить атомарную загрузку, за которой следует атомарное хранилище, если сохранение зависит от загрузки? Было бы крайне неинтуитивно, если бы это могло произойти, потому что если поток 1 спекулятивно из-за предсказания ветвления или по какой-либо причине записывает y = 1 до того, как условие в операторе if будет подтверждено как истинное, то, если позже он обнаружит, что условие разрешается как ложное, нет способа исправить ущерб (откатить изменения), поскольку другой поток, возможно, уже прочитал обновленное значение y!
Я не делаю думаю, что освобождение и приобретение семантики помогут в этом случае. Std::memory_order_release в y.store() будет использоваться для того, чтобы сделать более ранние записи видимыми для других потоков, которые видели значение y, но в этом случае поток1 не может ничего сделать, чтобы повлиять на видимость x в других потоках, поскольку x не был записан потоком1. В примерах семантики получения и выпуска, которые я видел в документации C++, речь идет только о паре потоков, где один является исключительно писателем, а другой — исключительно читателем.
Пример:
std::atomic x;
std::atomic y;

void thread1() {
int val = x.load(std::memory_order_relaxed);
if( val == 42 ){
y.store(1, std::memory_order_relaxed);
}
}

РЕДАКТИРОВАТЬ: меня попросили предоставить примеры, включая другие темы. Один касается упорядочивания хранилищ с точки зрения наблюдателей, а другой — о возможности спекулятивного выполнения хранилищ.
После того, как я приведу эти примеры и еще раз подумаю над проблемой, я могу уточнить вопрос:
  • Если у вас есть расслабленная атомарная загрузка, за которой следует расслабленное атомарное сохранение в другую переменную, и сохранение обусловлено (посредством оператора if) результатом загрузки (это то, что поток1 делает в пример), то действительно ли оператор if устанавливает ограждение между загрузкой и сохранением, то есть загрузка должна завершиться, прежде чем хранилище станет видимым для любого другого потока (или любого другого наблюдающего объекта, такого как устройство прямого доступа к памяти)? В терминологии C++ устанавливает ли оператор if событие-раньше между хранилищем и загрузкой? К сожалению, в документации C++ об упорядочивании памяти ничего не упоминается об условных хранилищах. В формализме C++ порядок событий устанавливается, если хранилище использует порядок выпуска. Но порядок выпуска также останавливает переупорядочение хранилище-хранилище, поэтому он более строгий, поэтому, если моя идея работает и вам нужно только упорядочить загрузку-хранилище, оператор if без каких-либо явных ограничений памяти может быть более эффективным, чем store_release. Я считаю, что вполне вероятно, что это всегда работает на реальном оборудовании, но документация C++ просто неполна и дает более слабые гарантии, чем необходимо, допуская поведение, которое никогда не может произойти на реальном оборудовании в реальном мире.
// This example is about ordering.
// Will thread3 see the new value of x, if thread1 has seen it?
std::atomic x;
std::atomic y;

void thread1() {
int val = x.load(std::memory_order_relaxed);
if( val == 42 ){
y.store(1, std::memory_order_relaxed);
}
}

void thread2() {
x.store(42, std::memory_order_relaxed);
}

void thread3() {
if( y.load(std::memory_order_relaxed) == 1 ){
std::atomic_thread_fence(memory_order_acquire);
int r = x.load(std::memory_order_relaxed);
assert(r == 42); // Can this go wrong?
}
}

// Similar, but we're putting it inside a loop
// to make it a little more interesting.
// This focuses on speculative execution.
std::atomic x;
std::atomic y;
std::atomic terminate;

void thread1() {
while( !terminate.load(std::memory_order_relaxed) ){

int val = x.load(std::memory_order_relaxed);
if( val == 42 ){
// Can y.store() be done speculatively?
y.store(1, std::memory_order_relaxed);
break;
}

}
}

void thread2() {
// This will count down and write to x,
// but should never actually store the value 42.
for(int idx = 10000000; idx > 42; --idx){
x.store(idx, std::memory_order_relaxed);
}
sleep_seconds(10);
terminate = true;
}

void thread3() {
while( !terminate.load(std::memory_order_relaxed) ){

if( y.load(std::memory_order_relaxed) == 1 ){
// This should never happen!
Open_Pandoras_Box();
Launch_Nuclear_Missiles();
Unleash_Armageddon();
break;
}

}
}


Подробнее здесь: https://stackoverflow.com/questions/797 ... f-the-stor
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»