首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >原子:当任务循环时,内存屏障是否会起作用?

原子:当任务循环时,内存屏障是否会起作用?
EN

Stack Overflow用户
提问于 2021-07-16 05:55:54
回答 1查看 152关注 0票数 0

因此,假设我有一个构造,其中两个任务同时运行(伪代码):

代码语言:javascript
复制
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;
    }
}

内存屏障应该位于标志变量处。据我理解,这意味着TaskB中的操作(b =a和c= 2b)是在TaskA中的分配(a = 5,b= 2,c= 3)之后执行的。但这是否也意味着,当TaskA仍在c= 2*b时,TaskB不可能第二次循环执行b=2?这在某种程度上是被阻止的吗,我们的循环开始时需要第二个屏障吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-16 06:21:21

如果您在发布存储后立即开始另一次非原子变量的写入,那么任何障碍都不能帮助您避免数据竞争UB。

在读取器读取这些变量时,对abc的非原子写入始终是可能的(而且很有可能),因此在C抽象机器中有数据争用UB。(在您的示例中,来自非同步的write+read of a、unsynced write+write of b、write+read of b和write+write of c)。

而且,即使没有循环,您的示例仍然无法安全地避免数据竞争UB,因为您的TaskB在flag.load之后无条件地访问abc。因此,不管您是否观察到作者发出的data_ready =1信号,您都可以这样做,即vars已经准备好被读取了。

当然,在实际实现中,重复编写相同的数据不太可能在这里造成问题,但b的读取值将取决于编译器的优化方式。但那是因为你的例子也写了。

主流CPU没有硬件竞争检测,因此它实际上不会出现故障或其他什么,而且如果您确实等待flag==1,然后只读取,即使编写器运行了更多相同值的赋值,您也会看到预期的值。( DeathStation 9000可以通过临时在该空间存储其他东西来实现这些赋值,因此内存中的字节实际上正在改变,而不是第一个发行版存储之前值的稳定副本,但这不是真正的编译器应该做的事情。不过,我不敢打赌,这似乎是一种反模式)。

这就是为什么无锁队列使用多个数组元素,或者seqlock不能这样工作的原因。( seqlock can't be implemented both safely and efficiently in ISO C++是因为它依赖于读取可能被撕裂的数据,然后检测撕裂;如果您使用窄的、足够宽松的原子来处理数据块,则会影响效率。)

想要再次写作的整个想法,也许在读者完成阅读之前,听起来很像你应该研究SeqLock的想法。https://en.wikipedia.org/wiki/Seqlock并在最后一段中看到我链接的答案中的其他链接。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68404071

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档