同时读和写到行(只读和存储)。当一个行在修改或读取模式下由内核拥有时,以及其他一些核心问题会在该行上存储操作(假设这些读写操作是std::C++::load和std::原子::存储在这个行上),会发生什么?该行是否被拉到发出写入的另一个核心中?或者写的东西会根据需要直接进入阅读核心吗?两者的不同之处在于,后者只会导致一次往返的开销,以读取线路的值。并且可能也会被并行化(如果存储和阅读发生在交错的时间点)
当考虑NUMA在并发应用程序中的后果时,就会出现这个问题。但是,当涉及到的两个核位于同一个NUMA节点时,问题就出现了。
其中有大量的体系结构。但就目前而言,对于英特尔Skylake或Broadwell发生的事情很好奇。
发布于 2019-08-05 23:17:11
首先,原子负载/存储与普通存储在编译到时没有什么特别之处。(虽然默认的seq_cst内存顺序可以编译为xchg,但是mov+mfence也是一个有效的(通常是较慢的)选项,在asm中与普通的发布存储区和一个完整的屏障无法区分。) xchg是一个原子RMW +一个完整的屏障。编译器将其用于完全屏蔽效应;交换的加载部分只是一个不必要的副作用。
这个答案的其余部分完全适用于任何x86存储区,或者内存目的地RMW指令的存储部分(不管它是否是原子的)。
最初,以前进行写操作的核心将在其L1d中使用MESI修改状态的行,前提是它尚未被逐出到L2或L3。
该行响应读取请求更改MESI状态(改为shared),或者对于存储区,执行写入的核心将发送RFO (所有权请求),并最终使行处于修改或排他状态。
在现代英特尔CPU上获取物理核之间的数据总是需要对共享的L3 (不一定是DRAM)进行回写。我认为即使在两个核位于单独的套接字上的多套接字系统中也是如此,因此它们并不真正地共享一个共同的L3,使用窥探(和窥探过滤)。
英特尔使用MESIF。AMD使用MOESI,它允许直接在内核之间共享脏数据,而无需首先对共享的外部级缓存进行回写。
有关详细信息,请参阅Which cache mapping technique is used in intel core i7 processor?
除了通过缓存/内存.之外,存储数据无法到达另一个核心。
你对在另一个核心上写“正在发生”的想法并不是任何事情是如何工作的。在遵守x86内存排序规则的情况下,我甚至看不出它是如何实现的:一个核心的存储按程序顺序显示为全局可见。我不明白如何将存储(到不同的缓存线)发送到不同的核心,并确保一个内核等待另一个内核将这些存储提交给它们各自拥有的缓存行。
即使对于弱有序的ISA来说,这也是不可信的。通常,当您读取或写入缓存行时,您将执行更多的reads+writes。通过内核之间的网格互连单独发送每个读或写请求将需要许多小消息。高吞吐量比低延迟更容易实现:更宽的总线可以做到这一点。对于高性能的负载,低延迟是必不可少的。如果线程在内核之间迁移,那么突然之间就会出现读/写缓存行的情况,而这些线在其他内核上都是L1d中的热点,这在CPU决定将缓存线迁移到访问它的核心之前是很可怕的。
L1d缓存是小的、快速的和相对简单的。对一个核心的reads+writes进行相对排序的逻辑,以及进行推测负载的逻辑,都是单个内核的内部逻辑。(存储缓冲区,或者在Intel上实际上是一个内存顺序缓冲区,用于跟踪推测负载以及存储。)
这就是为什么如果你能证明你不必这样做的话,你甚至应该避免接触一个共享变量。(或在适当的情况下使用指数退避)。以及为什么CAS循环应该只旋转只读,等待在尝试CAS之前查看它所寻找的值,而不是使用失败的lock cmpxchg尝试中的写来敲击缓存行。
https://stackoverflow.com/questions/57366900
复制相似问题