A应当是无锁的,因为它显然等价于long。C应该不是无锁的,因为它实在是太大了,目前没有寄存器能存下它。至于B我们就很难直接推断出来了。
对于x86架构的CPU,结构体B应当是无锁的,它刚刚好可以原子地使用MMX寄存器(64bit)处理。但如果它再大一点(比如塞一个int进去),它就不能无锁地处理了。
原子操作究竟是否无锁与CPU的关系很大。如果CPU提供了丰富的用于无锁处理的指令与寄存器,则能够无锁执行的操作就会多一些,反之则少一些。除此之外,原子操作能否无锁地执行还与内存对齐有关。正因如此,is_lock_free()才会是一个运行时方法,而没有被标记为constexpr。
内存屏障与memory order
CPU的缓存是存在“行”的,即CPU每次会将一段连续的数据加载到缓存中。要访问内存时,CPU会首先查找要访问的内存所在的这一行是否已经被加载到缓存中,如果命中则直接从缓存中的这一行取出对应的数据。更详细的内容请参考计算机组成原理,这里我们只需要知道CPU的缓存会以“行”为单位进行加载和释放即可。
Cache line会对原子操作的性能产生影响,具体表现为同时原子访问同一个Cache Line中的元素时,二者并不会同时进行,其中某一个访存会等待另一个原子访存完成。详细的内容请参考CppCon2017 C++ atomics, from basic to advanced。
算法
本文是对C++11引入的原子操作的使用简介,同时也是我观看CppCon2017 C++ atomics, from basic to advanced的一篇笔记。在本文中我略去了compare_exchange相关的内容,因为。。。我懒得写了,实际上compare_exchange_strong与compare_exchange_weak有不少值得记录的内容。compare_exchange_weak的“假失败”与CPU的设计有关,如果好奇的话就去看CppCon的演讲吧。
参考资料