实际上,无锁原子是无地址的吗?

时间:2018-07-22 08:28:50

标签: c++ shared-memory c++17 atomic lock-free

Boost.Interprocess是一个很棒的库,它简化了不同进程之间共享内存的使用。它提供互斥锁,条件变量和信号量,以便在共享内存中进行读写操作时实现同步。

但是,在某些情况下,这些(相对)性能密集的同步机制不是必需的-原子操作足以满足我的用例,并且可能会提供更好的性能。

不幸的是,Boost.Interprocess似乎没有原子。


C ++标准库提供了std::atomic类模板,该模板封装了需要原子操作的对象,并且还具有测试原子操作是否无锁的功能。但这并不要求无锁原子也必须无地址:[atomics.lockfree]/4只是鼓励无锁操作必须无地址,这同意cppreference

我想不出任何原因以非地址无关的方式实现无锁原子。在我看来,以无地址方式实现无锁原子非常容易。

由于使用原子而不是互斥量(来自Boost.Interprocess)时,我将获得显着的性能优势,因此似乎很想在此处降低标准兼容性并将std::atomic对象存储在共享内存中。


这个问题有两个部分:

  1. 在实践中,CPU是否以无地址方式实现无锁原子? (我只关心用于运行现代台式机和移动操作系统(例如Windows,MacOS,Linux,Android,iOS)的CPU,而不关心嵌入式系统)
  2. 为什么地球上的实现会使用无锁的非无地址原子?

1 个答案:

答案 0 :(得分:4)

是的,无锁原子在所有普通CPU上的所有C ++实现中都是无地址的,并且可以安全地用于进程之间的共享内存中。无锁原子 1 在进程之间不会很安全。每个进程将具有自己的锁哈希表(Where is the lock for a std::atomic?)。

C ++标准旨在使无锁原子在进程之间的共享内存中工作,但是在不定义术语等情况下,它只能达到“应该”的程度。

  

C++draft 29.5 Lock-free property

     

[注意:无锁操作也应无地址。也就是说,通过两个不同的地址对同一内存位置进行的原子操作将进行原子通信。实现不应依赖于任何每个进程的状态。 此限制允许通过多次映射到一个进程的内存以及通过在两个进程之间共享的内存进行通信。 —“请注意”

这是一个实施质量建议,很容易在当前硬件上实施,实际上,您必须努力设计一个在x86 / ARM / PowerPC /其他主流平台上违反该标准的deathstation9000 C ++实现CPU,而实际上是无锁的。


硬件为原子读取-修改-写入操作公开的机制基于MESI缓存一致性,该一致性仅关心物理地址。 x86 lock cmpxchg / lock add等使一个内核以Modified状态挂接到高速缓存行,因此在原子操作的中间没有其他内核可以读取/写入它。 (Can num++ be atomic for 'int num'?)。

大多数非x86体系结构都使用LL/SC,这使您可以编写一个重试循环,该循环仅在原子存储时才进行存储。 LL / SC可以在不引入地址的情况下以免等待方式模拟具有O(1)开销的CAS。

C ++无锁原子编译为直接使用LL / SC指令。有关x86示例,请参见我对num++问题的回答。有关使用LL / SC指令的compare_exchange_weakfetch_add的AArch64代码源的示例,请参见Atomically clearing lowest non-zero bit of an unsigned integer

原子纯负载或纯存储更容易,并且通过对齐的数据免费发生。在x86上,请参见Why is integer assignment on a naturally aligned variable atomic on x86?其他ISA具有类似的规则。


相关:我在Genuinely test std::atomic is lock-free or not的答案中加入了一些有关无地址的评论。我不确定它们是否有帮助或正确。 :/


脚注1

所有主流CPU都具有对象的无锁原子,直到指针的宽度为止。有些具有更宽泛的原子,例如x86具有lock cmpxchg16b,但并非所有实现都选择将其用于双倍宽度的无锁原子对象。检查C ++ 17 std::atomic::is_always_lock_freeATOMIC_xxx_LOCK_FREE(如果已定义)以进行编译时检测。

(某些微控制器无法将指针保存在单个寄存器中(或通过一次操作将其复制),但是通常不存在此类ISA的多核实现。)


  

为什么地球上的实现会使用无锁的非无地址原子?

我不知道在像普通现代CPU一样工作的硬件上有任何合理的理由。您可以想象通过将地址提交给某些

来执行原子操作的某种体系结构

我认为C ++标准希望尽可能避免约束非主流实现。例如C ++位于某种解释器之上,而不是针对“常规” CPU架构编译机器码。

IDK,如果您可以在松散耦合的共享内存系统(例如具有以太网链接的群集而不是共享内存或非一致性共享内存(必须显式刷新以便其他线程才能看到您的商店)的集群)上有效地实现C ++

我认为,主要是C ++委员会在不假设实现将如何执行原子力的情况下,没有假设实现将在多个进程可以设置共享内存的OS下运行程序的情况下。

>

他们可能正在想像将来的ISA,其中不可能使用无地址原子,但是我认为他们更可能不想谈论多个C ++程序之间的共享内存。该标准仅要求实施程序运行一个程序。

显然std::atomic_flag实际上被保证是无地址的Why only std::atomic_flag is guaranteed to be lock-free?,因此IDK为什么他们对实现选择将其实现为锁定的任何atomic<T>都没有相同的要求免费。