我在几个地方读到过宽松的排序可以生成唯一的 ID。我对此有疑问,因为如果两个线程同时调用:
uniqueId.fetch_add(1, std::memory_order::relaxed);
然后线程 A 增加的值可能对线程 B 不可见。这意味着,两个线程可以获得相同的唯一 ID。
出于这个原因,我宁愿使用
std::memory_order::acq_rel
你怎么看?
在实践中无法测试。
std::memory_order_*
是关于如何存储和加载到内存位置other 而不是原子对象本身同步。
单个原子对象的值在所有线程中总是一致的。它只有一个所有线程都同意的修改顺序,并且与每个线程中的加载/存储顺序一致,无论
std::memory_order_*
.
(然而,这仅适用于单独查看的每个原子对象。这同样不适用于多个原子对象。)
std::memory_order::relaxed
在您的情况下是否足够取决于生成的 ID 值是否将通过线程之间的其他共享对象(无论是否为原子)使用,但是表达式
uniqueId.fetch_add(1, std::memory_order::relaxed)
,即使在多个线程中使用,每个 ID 也只会生成一次(假设
uniqueId
指的是同一个 std::atomic
对象,没有其他存储应用于它并且没有溢出/环绕发生)。重要的是 fetch_add
本身是一个原子读-修改-写。加载后跟存储不是原子操作,也不能保证没有来自另一个线程的存储介入加载和存储之间。