简体   繁体   English

std::atomic:当任务循环时内存屏障是否存在?

[英]std::atomic: Does the memory barrier hold up when task loops around?

So say I have this construct where two Tasks run at the same time (pseudo code):所以说我有这样的构造,其中两个任务同时运行(伪代码):

int a, b, c;
std::atomic<bool> flag;

TaskA()
{
    while (1) {
        a = 5;
        b = 2;
        c = 3;
        flag.store(true, std::memory_order_release);
    }
}

TaskB()
{
    while (1) {
        flag.load(std::memory_order_acquire);
        b = a;
        c = 2*b;
    }
}

The memory barrier is supposed to be at the flag variable.内存屏障应该在标志变量处。 As I understand it this means, that the operations in TaskB (b = a and c = 2b) are executed AFTER the assignements in TaskA (a = 5, b = 2, c = 3).据我了解,这意味着 TaskB (b = a and c = 2b) 中的操作是在 TaskA (a = 5, b = 2, c = 3) 中的赋值之后执行的。 But does this also mean, that there's no way that TaskA could already loop around and execute b = 2 a second time when TaskB is at c = 2*b still?但这是否也意味着,当 TaskB 仍然处于 c = 2*b 时,TaskA 不可能已经循环并再次执行 b = 2 ? Is this somehow prevented, our would I need a second barrier at the start of the loop?这是否以某种方式阻止了,我们是否需要在循环开始时使用第二个屏障?

No amount of barriers can help you avoid data-race UB if you begin another write of the non-atomic variables right after the release-store.如果您在发布存储之后立即开始另一次写入非原子变量,则再多的障碍都无法帮助您避免数据竞争 UB。

It will always be possible (and likely) for some non-atomic writes to a , b , and c to be "happening" while your reader is reading those variables, therefore in the C abstract machine you have data-race UB.当您的读者正在读取这些变量时,对abc一些非原子写入总是有可能(并且很可能)“发生”,因此在 C 抽象机中,您有数据竞争 UB。 (In your example, from unsynced write+read of a , unsynced write+write of b , and the write+read of b , and write+write of c .) (在您的例子,从未同步的写+读的a ,未同步的写+写的b ,和写入+阅读的b ,和写+写c 。)

Also, even without loops, your example would still not safely avoid data-race UB, because your TaskB accesses a , b , and c unconditionally after the flag.load .此外,即使没有循环,您的示例仍然无法安全地避免数据竞争 UB,因为您的 TaskB 在flag.load之后无条件地访问abc So you do that stuff whether or not you observe the data_ready = 1 signal from the writer saying that the vars are ready to be read.因此,无论您是否观察到来自作者的 data_ready = 1 信号,表明 vars 已准备好被读取,您都要做这些事情。

Of course in practice on real implementations, repeatedly writing the same data is unlikely to cause problems here, except that the value read for b will depend on how the compiler optimizes.当然在实际的实现中,重复写入相同的数据在这里不太可能导致问题,除了读取b的值将取决于编译器如何优化。 But that's because your example also writes.但那是因为你的例子也写了。

Mainstream CPUs don't have hardware race detection, so it won't actually fault or something, and if you did actually wait for flag==1 and then just read, you would see the expected values even if the writer was running more assignments of the same values.主流 CPU 没有硬件竞争检测,所以它实际上不会出现故障或其他什么,如果你真的等待flag==1然后只是读取,即使作者正在运行更多的分配,你也会看到预期值相同的值。 (A DeathStation 9000 could implement those assignments by storing something else in that space temporarily so the bytes in memory are actually changing, not stable copies of the values before the first release-store, but that's not something that you'd expect a real compiler to do. I wouldn't bet on it, though, and this seems like an anti-pattern). (DeathStation 9000 可以通过在该空间中临时存储其他内容来实现这些分配,因此内存中的字节实际上正在发生变化,在第一次发布存储之前不是稳定的值副本,但这不是您期望真正的编译器做。不过,我不会打赌,这似乎是一种反模式)。


This is why lock-free queues use multiple array elements, or why a seqlock doesn't work this way.这就是无锁队列使用多个数组元素的原因,或者 seqlock 不能以这种方式工作的原因。 (A seqlock can't be implemented both safely and efficiently in ISO C++ because it relies on reading maybe-torn data and then detecting tearing; if you use narrow-enough relaxed atomics for the chunks of data, you're hurting efficiency.) 在 ISO C++ 中无法安全有效地实现 seqlock,因为它依赖于读取可能被撕裂的数据,然后检测撕裂;如果对数据块使用足够窄的放松原子,则会损害效率。)

The whole idea of wanting to write again, maybe before a reader has finished reading, sounds a lot like you should be looking into the idea of a SeqLock.想要再次写作的整个想法,也许在读者完成阅读之前,听起来很像您应该研究 SeqLock 的想法。 https://en.wikipedia.org/wiki/Seqlock and see the other links in my linked answer in the last paragraph. https://en.wikipedia.org/wiki/Seqlock并在最后一段的链接答案中查看其他链接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 std :: atomic访问是否充当内存屏障? - Does std::atomic access serve as a memory barrier? boost :: atomic是否充当硬件存储屏障? - Does boost::atomic act as a hardware memory barrier? 何时只有编译器的内存屏障(例如std :: atomic_signal_fence)有用吗? - When is a compiler-only memory barrier (such as std::atomic_signal_fence) useful? atomic_thread_fence(memory_order_seq_cst) 是否具有完整内存屏障的语义? - Does atomic_thread_fence(memory_order_seq_cst) have the semantics of a full memory barrier? 除了提供必要的保证之外,硬件 memory 屏障是否可以更快地看到原子操作? - Does hardware memory barrier make visibility of atomic operations faster in addition to providing necessary guarantees? 为什么 std::barrier 分配? - Why does std::barrier allocate? 记忆障碍如何运作? - How does memory barrier work? c++ atomic:函数调用会充当内存屏障吗? - c++ atomic: would function call act as memory barrier? 忙等待循环中是否需要内存屏障或原子操作? - Is memory barrier or atomic operation required in a busy-wait loop? C++ 在“线程屏障”同步模式上正确的原子内存排序 - C++ proper atomic memory ordering on a "thread barrier" synchronization pattern
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM