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

C++ 我们是否保证任何原子写入都会立即将原子变量的新值存储在主内存中?,c++,cpu-cache,memory-model,stdatomic,instruction-reordering,C++,Cpu Cache,Memory Model,Stdatomic,Instruction Reordering,所以,我读了很多关于指令和内存重新排序以及如何防止它的书,但我仍然没有回答一个问题,可能是因为我不够专心。我的问题是:我们是否保证任何原子写入都会立即将原子变量的新值存储在主内存中? 让我们来看一个小例子: std::atomic<bool> x; std::atomic<bool> y; std::atomic<int> count; void WritingValues() { x.store(true, std::memory_order_rela

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

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\u order\u released,并且不阻止任何指令重新排序或编译时的内存重新排序,我想这是一样的。但是,如果我们在写值中设置一些编译器障碍,以防止指令重新排序,那么一切都会正常吗?我的意思是,x.storetrue、std::memory\u order\u是否可以轻松地保证,该特定原子变量的写入将直接进入内存,而不会有任何延迟?或者x.loadstd::memory\u order\u轻松保证值将从内存中读取,而不是从具有无效值的缓存中读取?换句话说,这个存储只保证操作的原子性,并且与通常的非原子变量具有相同的内存行为,或者它也对内存行为有影响

 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和内存顺序,如果只读取一次,就没有“无效”值,true和false都可以。 由于松弛内存顺序显式保留,因此不执行任何排序。基本上,在您的情况下,它只意味着在从false切换到true之后,在某个点上,它将在所有其他进程中变为true,但不说明它将在何时发生。所以你唯一能确定的是,它在变为真后不会再次变为假。但在另一个线程中,它多长时间是错误的并没有限制。 此外,它还保证在另一个线程中不会看到任何部分写入的变量,但bools的情况并非如此。 你需要在这里使用aquire和release。即使这样,也不能保证实际内存本身,只能保证程序的行为,缓存同步也可以做到这一点,即使没有将数据反弹回内存并使其产生泡沫

不,它不是,事实上,给定bool和内存顺序,如果只读取一次,就没有“无效”值,true和false都可以。 由于松弛内存顺序显式保留,因此不执行任何排序。基本上,在您的情况下,它只意味着在从false切换到true之后,在某个点上,它将在所有其他进程中变为true,但不说明它将在何时发生。所以你唯一能确定的是,它在变为真后不会再次变为假。但在另一个线程中,它多长时间是错误的并没有限制。 此外,它还保证在另一个线程中不会看到任何部分写入的变量,但bools的情况并非如此。
你需要在这里使用aquire和release。即使这样,也不能保证实际内存本身,只能保证程序的行为,缓存同步也可以做到这一点,即使没有将数据反弹回内存并使其产生泡沫
std::memory_order_Released允许在单个函数中对指令进行某种重新排序。参见问题示例。这几乎和你的问题一样,但你的记忆顺序是在ReadValues中放松的,而不是在acquire中放松的。在该函数中,由于宽松条件编译器重新排序等原因,变量y上的自旋锁可能放置在计数器增量之后。。在任何情况下,断言都可能失败,因为在x写入值之前,y可能被设置为true,这是由于在类似问题中引用的memory_order_允许的内存重新排序。

由于所有加载和存储指令都是原子指令,它们都是一条机器指令,因此两个线程在写入值时不会相互中断加载或存储指令的中间部分

您的问题的标题是:我们是否保证任何原子写入都会立即将原子变量的新值存储在主内存中?。但是an的定义是,它不能被上下文切换、硬件中断、软件期望所中断——什么都不能

std::memory_order_Released允许在单个函数中对指令进行某种重新排序。参见问题示例。这几乎和你的问题一样,但你的记忆顺序是在ReadValues中放松的,而不是在acquire中放松的。在这个
函数由于宽松条件编译器重新排序等原因,变量y上的自旋锁可能放置在计数器增量之后。。在任何情况下,断言都可能失败,因为在x写入值之前,y可能被设置为true,这是由于在类似问题中引用的内存顺序允许内存重新排序。

您的问题实际上没有意义,无法回答。在C++中,正确的概念是排序。在同一执行线程中,依次修改一个原子变量将第一个原子变量排序到第二个原子变量之后。但这些都不能确定不同的执行线程是否观察到这些原子变量的变化。为了确定这一点,有必要确定这些执行线程之间的顺序。“这方面也有很多规则。我不能完全确定我是否清楚地理解你,”萨姆瓦沙维奇说。你说的一个又一个修改一个原子变量是什么意思。但是指令重新排序呢?据我所知,这种情况很容易发生。我对这些规则也有点困惑。其中一个可能的变体就是使用记忆屏障,这就是我在这里所说的。我只是想知道原子写入是否有可能不会立即写入内存。原子写入所能保证的就是没有其他线程会看到对象的部分内容。其他线程在更改之前或之后查看该值。对于布尔人来说,这几乎毫无意义。至于其他线程是否立即看到写入,这将永远是一个谜,因为一个线程无法确定另一个线程是否写入了某些内容。那就是排序。例如:锁定互斥锁后,一个线程将看到另一个线程在解锁同一互斥锁之前所做的一切,因为这是按顺序排列的。@SamVarshavchik但是MESI/MOESI协议呢?我认为这是专门为缓存一致性问题开发的。所以线程知道,如果内存被修改,因为它有一个特殊的修改器。不管怎么说,我猜我们在谈论不同的事情,或者我只是误解了你。@curiousguy是的,这就是MESI/MOESI协议所代表的意思。你的问题实际上毫无意义,无法回答。在C++中,正确的概念是排序。在同一执行线程中,依次修改一个原子变量将第一个原子变量排序到第二个原子变量之后。但这些都不能确定不同的执行线程是否观察到这些原子变量的变化。为了确定这一点,有必要确定这些执行线程之间的顺序。“这方面也有很多规则。我不能完全确定我是否清楚地理解你,”萨姆瓦沙维奇说。你说的一个又一个修改一个原子变量是什么意思。但是指令重新排序呢?据我所知,这种情况很容易发生。我对这些规则也有点困惑。其中一个可能的变体就是使用记忆屏障,这就是我在这里所说的。我只是想知道原子写入是否有可能不会立即写入内存。原子写入所能保证的就是没有其他线程会看到对象的部分内容。其他线程在更改之前或之后查看该值。对于布尔人来说,这几乎毫无意义。至于其他线程是否立即看到写入,这将永远是一个谜,因为一个线程无法确定另一个线程是否写入了某些内容。那就是排序。例如:锁定互斥锁后,一个线程将看到另一个线程在解锁同一互斥锁之前所做的一切,因为这是按顺序排列的。@SamVarshavchik但是MESI/MOESI协议呢?我认为这是专门为缓存一致性问题开发的。所以线程知道,如果内存被修改,因为它有一个特殊的修改器。不管怎样,我想我们谈论的是不同的事情,或者我只是误解了你。@curiousguy是的,这就是MESI/MOESI协议所代表的是的,这就是内存顺序释放和获取的目的。使用release写入会将其释放给使用acquire读取它的任何人。release只会释放其他先前的内存操作。释放操作完成的操作不受影响。是的,这就是内存顺序释放和获取的目的。使用release写入会将其释放给使用acquire读取它的任何人。release只会释放其他先前的内存操作。是的,我在问题中也写了同样的问题:D.我知道,断言可以触发,我在上面注意到了。我也不是要打断别人,这是可以理解的。我不确定缓存的一致性和备忘
在这里,我认为原子变量可以防止任何指定内存顺序的内存重新排序问题,但我错了。现在我知道答案了,谢谢:是的,我在问题中也写了同样的问题:D。我知道,断言可以开火,我注意到了上面的问题。我也不是要打断别人,这是可以理解的。我不确定这里的缓存一致性和内存行为,我认为原子变量可以防止任何指定内存顺序的内存重新排序问题,但我错了。现在我知道答案了,谢谢: