使用“memory_order::relaxed”或“memory_order::acq_rel”生成唯一ID?

Phi*_*ppe 0 c++ atomic memory-model stdatomic

我在几个地方读到,宽松的排序可以生成唯一的 ID。我对此表示怀疑,因为如果两个线程同时调用:

uniqueId.fetch_add(1, std::memory_order::relaxed);

那么线程 A 递增的值可能对线程 B 不可见。这意味着,两个线程可以获得相同的唯一 ID。

出于这个原因,我宁愿使用std::memory_order::acq_rel

你怎么认为?

在实践中无法测试。

use*_*522 7

std::memory_order_*是关于如何同步存储和加载到原子对象本身以外的内存位置。

单个原子对象的值在所有线程中始终保持一致。它具有所有线程都同意的一个修改顺序,并且与每个线程中加载/存储的顺序一致,无论std::memory_order_*.

(但是,这仅适用于单独查看的每个原子对象。这不适用于多个原子对象之间。)

在您的情况下是否std::memory_order::relaxed足够取决于生成的 ID 值是否将通过线程之间的其他共享对象(无论是否原子)使用,但是表达式

uniqueId.fetch_add(1, std::memory_order::relaxed)
Run Code Online (Sandbox Code Playgroud)

,即使在多个线程中使用时,每个 ID 也只会生成一次(假设uniqueId引用同一个std::atomic对象,没有其他存储应用于它,并且不会发生溢出/环绕)。但重要的是,它fetch_add本身就是一个原子的读-修改-写。加载后跟存储不会是原子操作,并且不能保证来自另一个线程的存储不会介入加载和存储之间。

  • 顺便说一句,出于这个原因,RMW 操作始终加载“最新值”的保证(创建一个修改顺序,其中每个增量都被看到一次),而不是更快地及时查看存储(线程间延迟或避免“陈旧”) “值。) (3认同)