7

我是在内存模型的意义上专门问的。http://en.cppreference.com/w/cpp/atomic/memory_order

我问是因为我想知道我是否可以std::memory_order_consume在下面使用 a :

mLocalMemPtr1 和 2 以及 mAtomicMemPtr 是指向共享缓冲区的指针。

在生产者线程中,我正在做:

for (int x = 0; x < 10; ++x)
{
    ++mLocalMemPtr1
    *mLocalMemPtr1 = x;       // <========= A
    mAtomicMemPtr.store(mLocalMemPtr1, std::memory_order_release);
}

在消费者中:

tempMemPtr = mAtomicMemPtr.load(std::memory_order_consume);
while (tempMemPtr != mLocalMemPtr2)
{
    ++mLocalMemPtr2;
    int test = *mLocalMemPtr2;   // <======== B
    doSomeLongRunningThing(test);
    tempMemPtr = mAtomicMemPtr.load(std::memory_order_consume);
}

那么依赖链是 tempMemPtr -> mLocalMemPtr2 -> test -> doSomeLongRunningThing 吗?

我特别担心B之前可能会被执行A。我知道我可以使用 a std::memory_order_acquire,但如果条件语句导致内存顺序依赖,我可以使用 consume (更轻量级)。

4

3 回答 3

3

Cpp参考

发布-消费订购

如果线程 A 中的原子存储标记为 std::memory_order_release,线程 B 中来自同一变量的原子加载标记为 std::memory_order_consume,则所有内存写入(非原子和宽松原子)从线程 A 的角度来看,原子存储在线程 B 中成为可见的副作用,也就是说,一旦原子加载完成,如果线程 B携带数据依赖项,则保证线程 B 可以看到线程 A写入内存的所有内容原子负荷。

1.10.10:

评估 A 在评估 B 之前是依存排序的,如果

— A 对原子对象 M 执行释放操作,并且在另一个线程中,B 对 M 执行消耗操作并读取以 A (...) 为首的释放序列中由任何副作用写入的值

1.10.9:

如果 - 将 A 的值用作 B 的操作数,则评估 A 对评估 B 具有依赖性,除非:

— B 是对 std::kill_dependency (29.3) 的任何特化的调用,或

— A 是内置逻辑 AND(&&,参见 5.14)或逻辑 OR(||,参见 5.15)运算符的左操作数,或

— A 是条件 (?:, 见 5.16) 运算符的左操作数,或

— A 是内置逗号 (,) 运算符 (5.18) 的左操作数;(...)

基于这些事实,我说mLocalMemPtr2应该同步。但是,仍然存在评估顺序的问题。

if (atomic.load(std::consume) < x)

首先评估哪个是未指定的。不能保证(因为我在标准中找不到)编译器将首先执行消耗操作,刷新共享缓冲区,然后加载atomic ,然后 x.

由于没有找到以“希望”方式评估操作数的证据,我说如果没有显式分解原子负载mLocalMemPtr2,它将无法工作,并且 CPU 可能会读取mLocalMemPtr2. memory_order_acquire在这里不会有太大变化,因为mLocalMemPtr2它带有数据依赖性。

于 2013-05-06T11:14:59.450 回答
0

我相信通过排序,编译器实际上可以提前consume制作整个副本。mSharedBuffer您需要acquire语义来使以前缓存的变量副本无效,而不是mAtomicMemLocPtr .

于 2013-05-06T03:32:58.920 回答
0

如果要按字面意思来理解它们,那么它们在携带依赖。那我会说

tempMemPtr = mAtomicMemPtr.load(std::memory_order_consume);

将依赖项带入循环的条件(将其视为布尔变量标志)。但是该条件在任何循环体操作中都不会被读取为操作数(也不会写入由循环体中的另一个操作读取的对象)。因此,需要一个获取操作,以使在释放之前排序的操作也发生在获取之后的操作(读取该写入释放)之前,而不依赖于消耗操作和主体中的操作之间的数据依赖关系循环

也许涉及发布消费语义的解决方案是:

tempMemPtr = mAtomicMemPtr.load(std::memory_order_consume);
while (tempMemPtr != mLocalMemPtr2)
{
    mLocalMemPtr2 = tempMemPtr; // that line adds the dependency needed 
    ++mLocalMemPtr2;
    int test = *mLocalMemPtr2;
    doSomeLongRunningThing(test);
    tempMemPtr = mAtomicMemPtr.load(std::memory_order_consume);
}
于 2018-12-13T11:16:48.093 回答