在实践中,无锁原子是否无地址?

Ber*_*ard 7 c++ atomic shared-memory lock-free c++17

Boost.Interprocess是一个很棒的库,可以简化不同进程之间共享内存的使用.它提供互斥锁,条件变量和信号量,允许在从共享内存中写入和读取时进行同步.

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

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


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

我想不出为什么会以非地址方式实现无锁原子的任何理由.在我看来,以无地址的方式实现无锁原子相当容易.

因为在使用原子而不是互斥体(来自Boost.Interprocess)时我会获得显着的性能优势,所以在这里折扣标准兼容性并将std::atomic对象存储在共享内存中似乎很诱人.


这个问题分为两部分:

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

Pet*_*des 7

是的,无锁原子在所有普通 CPU 上的所有 C++ 实现上都是无地址的,并且可以安全地用于进程之间的共享内存。 不过,非无锁原子1在进程之间 并不安全。每个进程都有自己的锁哈希表(std::atomic 的锁在哪里?)。

\n

C++ 标准希望无锁原子在进程之间的共享内存中工作,但它只能达到“应该”,而无需定义术语等。

\n
\n

C++draft 29.5 无锁属性

\n

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

\n
\n

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

\n
\n

原子读-修改-写操作的硬件公开机制基于仅关心物理地址的 MESI 缓存一致性。x86 lock cmpxchg//lock add 等使核心挂在修改状态的缓存行上,因此其他核心无法在原子操作过程中读取/写入它。(num++ 对于 'int num' 可以是原子的吗?)。

\n

大多数非 x86 架构使用LL/SC,它允许您编写一个重试循环,仅在原子性的情况下才执行存储。LL/SC 可以以无等待的方式以 O(1) 开销模拟 CAS,而无需引入地址。

\n

C++ 无锁原子编译为直接使用 LL/SC 指令。请参阅我num++对 x86 示例问题的回答。有关使用 LL/SC 指令的 AArch64 代码生成的一些示例,请参阅原子清除无符号整数的最低非零位compare_exchange_weakfetch_add

\n

原子纯加载或纯存储更容易,并且在数据对齐的情况下免费发生。在 x86 上,请参阅为什么自然对齐变量上的整数赋值在 x86 上是原子的? 其他 ISA 也有类似的规则。

\n
\n

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

\n
\n

脚注1

\n

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

\n

(某些微控制器无法在单个寄存器中保存指针(或通过单个操作复制它),但此类 ISA 通常没有多核实现。)

\n
\n
\n

到底为什么实现要使用无锁的非无地址原子?

\n
\n

我不知道硬件上有什么合理的理由可以像普通的现代 CPU 一样工作。您可以想象某种架构,通过将地址提交给某些人来执行原子操作

\n

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

\n

如果您可以在松散耦合的共享内存系统(例如具有以太网链接而不是共享内存或非连贯共享内存(必须显式刷新以供其他线程查看您的存储)的集群)上有效地实现 C++,我不知道。

\n

我认为主要是 C++ 委员会无法对如何实现原子性给出太多说明,除非假设实现将在多个进程可以设置共享内存的操作系统下运行程序。

\n

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

\n

显然std::atomic_flag实际上保证是无地址的为什么只有 std::atomic_flag 保证是无锁的?,所以我不知道为什么他们不对atomic<T>实现选择实现为无锁的任何要求提出相同的要求。

\n


归档时间:

查看次数:

660 次

最近记录:

7 年,3 月 前