宽松的原子计数器安全吗?

Is a relaxed atomic counter safe?

根据 C++11 内存模型,以下代码是否保证 return 计数器的预期值 (40,000,000)? ( 限于 x86)。

#include <atomic>
#include <thread>
using namespace std;

void ThreadProc(atomic<int>& counter)
{
    for (int i = 0; i < 10000000; i++)
        counter.fetch_add(1, memory_order_relaxed);
}

int main()
{
    #define COUNT 4
    atomic<int> counter = { 0 };
    thread threads[COUNT] = {};

    for (size_t i = 0; i < COUNT; i++)
        threads[i] = thread(ThreadProc, ref(counter));

    for (size_t i = 0; i < COUNT; i++)
        threads[i].join();

    printf("Counter: %i", counter.load(memory_order_relaxed));
    return 0;
}

特别是,将放宽原子坐标,使两个线程不会同时读取当前值,独立地递增它,并且都写入它们递增的值,有效地失去之一写?

规范中的某些行似乎表明在上面的示例中,计数器 必须 始终为 40,000,000。

[Note: operations specifying memory_order_relaxed are relaxed with respect to memory ordering. Implementations must still guarantee that any given atomic access to a particular atomic object be indivisible with respect to all other atomic accesses to that object. — end note

.

Atomic read-modify-write operations shall always read the last value (in the modification order) written the write associated with the read-modify-write operation.

.

All modifications to a particular atomic object M occur in some particular total order, called the modification order of M. If A and B are modifications of an atomic object M and A happens before (as defined below) B, then A shall precede B in the modification order of M, which is defined below.

这个演讲也支持上述代码没有竞争的观点。 https://www.youtube.com/watch?v=KeLBd2EJLOU&feature=youtu.be&t=1h9m30s

在我看来,原子操作的不可分割的顺序,但我们无法保证顺序是什么。因此,所有增量都必须在没有我上面描述的竞争的情况下发生 'one before the other'。

但是有一些事情可能指向另一个方向:

Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.

一位同事告诉我,Sutter 的演讲中存在已知错误。虽然我还没有找到任何来源。

C++ 社区的多个成员比我暗示的更聪明,可以缓冲宽松的原子添加,以便后续的宽松原子添加可以读取和操作陈旧值。

您问题中的代码是免费的;所有的增量都是有序的,40000000的结果是有保证的。
您问题中的参考文献包含标准中的所有相关引述。

其中所说的原子存储应在合理时间内可见的部分仅适用于单个存储。
在您的情况下,计数器通过原子读取-修改-写入操作递增,并且保证在修改顺序中的最新操作。

Multiple members of the C++ community (...) have implied that a relaxed atomic add could be buffered such that a subsequent relaxed atomic add could read and operator on the stale value.

这是不可能的,只要修改是基于原子读-修改-写操作。
如果标准不能保证可靠的结果,原子增量将毫无用处