我们是否可以保证任何原子写入都会立即将原子变量的新值存储在主内存中?

Do we have the guarantee that any atomic write will store the new value of the atomic variable in the main memory immediately?

所以,我阅读了很多关于指令和内存重新排序以及我们如何防止它的内容,但我仍然没有回答一个问题(可能是因为我不够专心)。我的问题是:我们是否可以保证任何原子写入都会立即将原子变量的新值存储在主内存中? 我们来看一个小例子:

std::atomic<bool> x;
std::atomic<bool> y;
std::atomic<int> count;
void WritingValues()
{
   x.store(true, std::memory_order_relaxed);
   y.store(true, std::memory_order_relaxed);
}
void ReadValues()
{
   while( !y.load(std::memory_order_relaxed) );
   if( x.load(std::memory_order_relaxed) )
       ++count;
}
int main()
{
   x = false;
   y = false;
   count = 0;
   std::thread tA(WritingValues);
   std::thread tB(ReadValues);
   tA.join();
   tB.join();
   assert( count.load() != 0 );
}

所以,这里我们的断言肯定会触发,因为我们使用 std::memory_order_relaxed 并且不会阻止任何指令重新排序(或编译时的内存重新排序,我想是一样的)。但是,如果我们在 WritingValues 中放置一些 compiler barrier 以防止 instruction reordering,是否一切正常?我的意思是,x.store(true, std::memory_order_relaxed) 是否保证 特定原子变量 的写入将是直接进入内存,没有任何延迟?还是 x.load(std::memory_order_relaxed) 保证值将从内存中读取,而不是从具有无效值的缓存中读取?换句话说,这个store保证操作的原子性并且和通常的非原子变量具有相同的内存行为,或者它也对内存行为有影响?

 I mean, does x.store(true, std::memory_order_relaxed) guarantees, that the  
 of that particular atomic variable will be directly into the memory,  
 without any latency?  

不,实际上给定 bool 和 memory order relaxed 如果你只读一次就没有 'invalid' 值,true 和 false 都可以。
由于宽松的内存顺序明确保留,因此不执行任何排序。基本上,在您的情况下,这仅意味着在从 false 变为 true 之后,在某个时候它将对所有其他进程变为 true,但没有说明 'whent' 它会发生。所以这里唯一可以确定的是,它变成真后不会再变成假了。但是在另一个线程中它会为假多长时间没有限制。
它还保证您不会在另一个线程中看到任何部分写入的变量,但布尔值几乎不是这种情况。
你需要在这里使用 aquire 和 release 。即使这样也不能对实际内存本身提供任何保证,只能保证程序行为,缓存同步甚至可以在不将数据弹回内存的情况下发挥作用。

由于所有加载和存储指令都是原子的,因此它们每个都是一条机器指令,因此两个线程永远不会 "interrupt each other" 在加载或存储指令的 "middle" 中。

您的问题标题是"Do we have the guarantee that any atomic write will store the new value of the atomic variable in the main memory immediately?"。但是 atomic instruction 定义 是它不能被上下文切换、硬件中断、软件预期中断——什么都没有!

std::memory_order_relaxed 允许在单个函数中对指令进行一些重新排序。参见类似问题中的示例 this question. It is almost the same as your question but you have memory_order_relaxed in ReadValues() instead of memory_order_acquire. In this function it is possible that the spinlock on variable y is placed after the counter increment due to the relaxed condition (compiler reordering etc.). In any case the ASSERT may fail because y may be set to true before x is in WriteValues() due to the memory reordering allowed by memory_order_relaxed (referencing the answer