Я не делаю думаю, что освобождение и приобретение семантики помогут в этом случае. 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++ просто неполна и дает более слабые гарантии, чем необходимо, допуская поведение, которое никогда не может произойти на реальном оборудовании в реальном мире.
// 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
Мобильная версия