代码之家  ›  专栏  ›  技术社区  ›  Bernard

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

  •  7
  • Bernard  · 技术社区  · 7 年前

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

    然而,在某些情况下,这些(相对而言)性能密集型的同步机制是不必要的——原子操作对于我的用例来说已经足够了,而且可能会提供更好的性能。

    不幸的是,boost.interprocess似乎没有原子。


    C++标准库提供了 std::atomic 类模板,它封装了其操作需要是原子的对象,还具有测试原子操作是否无锁的函数。但事实并非如此 要求 无锁原子也要无地址: [atomics.lockfree]/4 仅仅 鼓励 无锁操作是无地址的,这与 cppreference 是的。

    我想不出为什么会有人以非地址自由的方式实现无锁原子在我看来,以无地址的方式实现无锁原子似乎要容易得多。

    由于在使用原子而不是互斥(来自boost.interprocess)时,我将获得显著的性能优势,因此在这里似乎很容易忽略标准遵从性并存储 标准:原子 共享内存中的对象。


    这个问题分为两部分:

    1. CPU在实践中是否以无地址的方式实现无锁原子(我只关心用于运行现代桌面和移动操作系统(如Windows、MacOS、Linux、Android、iOS)的cpu,而不关心嵌入式系统)
    2. 为什么一个实现会使用无地址、无锁的原子?
    1 回复  |  直到 7 年前
        1
  •  4
  •   Peter Cordes    7 年前

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

    C++标准打算在进程间共享内存中使用无锁原子,但它只能在不定义术语的情况下尽可能地使用“应该”。

    C++draft 29.5 Lock-free property

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

    这是一个在当前硬件上很容易实现的实现质量的推荐,事实上,你必须努力设计一个DexSturt9900c++实现,它在X86/ARM/PowerPC /其他主流CPU上被破坏,而实际上是被锁定的。


    硬件为原子读修改写操作公开的机制是基于只关心物理地址的mesi缓存一致性。x86 lock cmpxchg / lock add /etc.使核心在修改状态下挂接到缓存线上,这样其他核心就不能在原子操作过程中读/写它。( Can num++ be atomic for 'int num'? )

    大多数非x86体系结构使用 LL/SC ,它允许您编写一个重试循环,仅当它是原子的时才执行存储。LL/SC可以以无等待的方式模拟开销为O(1)的CAS,而不引入地址。

    C++无锁原子汇编直接使用L/SC指令。看我的答案 num++ 关于x86示例的问题。见 Atomically clearing lowest non-zero bit of an unsigned integer 关于AArch64的一些示例 compare_exchange_weak fetch_add 使用ll/sc指令。

    原子纯加载或纯存储更容易,并且可以免费使用对齐的数据在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_free ATOMIC_xxx_LOCK_FREE 如果已定义,则用于编译时检测。

    (有些微控制器不能在一个寄存器中保存指针(或通过一个操作复制指针),但通常没有这种isa的多核实现。)


    为什么一个实现会使用无地址、无锁的原子?

    我不知道有任何合理的理由在硬件上工作,任何像正常的现代CPU。你可以想象一些体系结构,通过将地址提交给

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

    IDK,如果您可以有效地在一个松散耦合的共享内存系统上实现C++,比如一个带有以太网链接的集群,而不是共享内存,或者非相干共享内存(必须显式地刷新其他线程来查看您的存储)。

    我认为主要是C++委员会对原子论怎么说不多。 必须 在不假设实现将在操作系统下运行程序的情况下实现,其中多个进程可以设置共享内存。

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

    显然 std::atomic_flag 实际上保证是免费的 Why only std::atomic_flag is guaranteed to be lock-free? ,所以我想知道为什么他们对任何 atomic<T> 实现选择实现为无锁。