19

std::atomicstoreload接受参数等std::memory_order函数。参数可以在运行时确定,就像任何其他函数参数一样。但是,实际值可能会影响编译期间代码的优化。考虑以下:

std::atomic<int> ai1, ai2;
int value = whatever;

void foo() {
    std::memory_order memOrd = getMemoryOrder();
    register int v = value; // load value from memory
    ai1.store(v, memOrd);   // dependency on v's value
    ai2.store(1, memOrd);   // no dependency. could this be move up?
}

如果memOrd碰巧memory_order_relaxed,第二家商店可以安全地移到第一家之前。这将在加载value和使用它之间增加一些额外的工作,这可能会防止其他需要的停顿。但是,如果memOrdmemory_order_seq_cst,则不应允许切换存储,因为某些其他线程可能会依赖ai1已设置为valueifai2设置为 1。

我想知道为什么将内存顺序定义为运行时参数而不是编译时间。在决定最佳内存操作语义之前,是否有任何理由让某人在运行时检查环境?

4

3 回答 3

8

这是作为运行时参数而不是编译时参数实现的原因是为了启用组合

假设您正在编写一个函数,该函数使用提供的原子操作来执行相当于加载操作的操作,但在更高级别的构造上操作。通过将内存顺序指定为运行时参数,更高级别的负载可以将用户提供的内存顺序参数传递给提供排序所需的低级别原子操作,而无需高级操作必须是模板。

通常,原子指令是内联的,如果内存顺序参数实际上是一个编译时常量,编译器将消除对内存顺序参数的测试。

于 2012-12-19T07:52:09.063 回答
4

它只是一个允许memory_order运行时指定的接口规范。它不需要实现来使用该津贴。

例如memory_order_seq_cst,无论您指定什么,x86 硬件都可能是您所得到的。memory_order_relaxed由于硬件缓存一致性协议,只是不可用。

在其他硬件上,您可能能够针对编译时间已知顺序进行优化,实现可能会提供利用默认参数的额外重载。

于 2012-12-18T22:28:24.757 回答
0

C++ 的作者可以将 memory_order 实现为编译时功能,而不是运行时功能。然而,他们不会因此得到任何好处。任何能够理解内存顺序的编译器都可以轻松优化 x.load(memory_order_acq) 等明显的情况,因此它们不会从它作为编译时特性中受益。

同时,使用运行时特性意味着他们不必为内存顺序引入任何新的符号。它们只是函数参数。这意味着它们获得了与编译时版本相同的好处,但复杂性更低。

同时,对于更简单的编译器来说也非常方便,因为它们可以将 atomic 实现为普通类,而无需特殊处理。

T atomic<T>::compare_exchange_strong(T& compare, T exchange, memory_order order)
{
    lockBeforeUsing(order); // handle the acquire part of the memory order
    if (mValue == compare) {
        compare = mValue;
        mValue = compare;
    } else {
        compare = mValue;
    }
    lockAfterUsing(order); // handle the release part of the memory order
}
于 2013-09-03T05:41:20.780 回答