在Go (和其他语言如c++)中使用atomics时,建议使用原子加载操作来读取并发写入的值。
如果原子写入(无论是存储还是整数增量)的定义(据我理解)是,没有线程可以查看部分写入,那么为什么需要原子加载?
如果仅在内存地址上使用原子存储,内存地址的普通负载是否总是安全的?
发布于 2021-07-09 00:23:49
这个答案主要针对C和C++,因为我并不直接熟悉其他许多语言中的atomics,但我怀疑它们是相似的。
在某些情况下,许多实际机器确实是这样工作的。例如,在x86-64上,普通加载指令对于普通存储区是原子的,或者是锁定的读-修改-写入指令。因此,对于可以加载单个指令的类型,原则上可以使用普通赋值,避免撕裂。
但在某些情况下,这是行不通的。例如:
atomic加载函数知道要使用锁,普通的赋值是不会的。long long int。一个普通的加载将执行两个32位整数加载指令(这些指令分别是原子的),所以即使存储是原子的,它也可能发生在两者之间。但是atomic加载函数可以发出64位浮点或SIMD负载,虽然效率较低,但可以在一个原子指令中完成。关于哥德螺栓的实例。因此,当存储和加载和都使用所提供的atomic函数时,该语言只承诺原子性。-C或C++的“定义”不准确。通过要求程序员始终使用atomic负载,该语言提供了一个“钩子”,实现可以在需要时采取适当的操作。在普通负载已经足够的情况下,实现可以相应地进行优化,而不会丢失任何东西。
另一点是,atomic加载提供了一个位置,以便在需要的时候设置一个内存屏障(除relaxed之外的任何排序)。一些体系结构包括带有内置屏障的加载指令(例如a 64的ldar),并且在语言级别将屏障作为负载的一部分,使编译器更容易利用这一点。如果您必须执行常规的赋值,然后调用屏障函数,那么编译器就很难知道它可以将它们优化到ldar中。
https://stackoverflow.com/questions/68309532
复制相似问题