spin_lock()
的实现方式,最初来自this answer:void spin_lock(volatile bool* lock) {
for (;;) {
// inserts an acquire memory barrier and a compiler barrier
if (!__atomic_test_and_set(lock, __ATOMIC_ACQUIRE))
return;
while (*lock) // no barriers; is it OK?
cpu_relax();
}
}
我已经了解的内容:
volatile
防止编译器在每次while
循环迭代中优化掉*lock
的重新读取;volatile
不会插入内存或编译器屏障;- 这样的实现实际上在 GCC 中适用于
x86
(例如在 Linux 内核中)和一些其他架构; - 对于通用架构,
spin_lock()
实现中至少需要一个内存和编译器屏障;此示例在__atomic_test_and_set()
中插入它们。
问题:
在这里使用
volatile
是否足够,或者是否有任何体系结构或编译器需要内存或编译器屏障或原子操作在while
循环中?1.1 根据
C++
标准?1.2 实际上,对于已知的体系结构和编译器,特别是对于GCC和它支持的平台而言?
- 这个实现在GCC和Linux支持的所有体系结构上是否安全?(至少在某些体系结构上效率低下,对吧?)
while
循环根据C++11
及其内存模型是否安全?
有几个相关的问题,但我无法从中构建出明确且明确的答案:
-
原则上:是的,如果程序执行从一个核心转移到另一个核心,它可能无法看到在之前的核心上发生的所有写操作。
-
在几乎所有现代架构中,缓存(如L1和L2缓存)由硬件保证一致。没有必要刷新任何缓存以使内存对其他CPU可见。
volatile
读取不能保证同步缓存。它应该用于设备接口,而不是用于线程。请参见 Volatile and multithreading: is the following thread safe? - Bo Perssonvolatile
不会创建这样的屏障。 - davmac