首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >易失性写入的成本

易失性写入的成本
EN

Stack Overflow用户
提问于 2017-04-18 06:34:56
回答 1查看 116关注 0票数 2

我研究了在x86硬件中使用java语言进行易失性写操作的成本。我计划在一个共享内存位置上使用Unsafe的putLongVolatile方法。查看其实现,putLongVolatile get在Link中被转换为Unsafe_SetLongVolatile,随后被转换为AtomicWrite,后跟围栏Link

简而言之,每个易失性写操作都会被转换为原子写操作,然后是一个完整的栅栏(x86中的mfence或锁定的add指令)。

问题:

1)为什么x86需要围栏()?由于存储-存储排序,一个简单的编译器屏障还不够吗?一道完整的栅栏看起来非常昂贵。

2) putLong是不是更好的替代不安全的putLongVolatile?它在多线程的情况下会工作得很好吗?

EN

回答 1

Stack Overflow用户

发布于 2020-05-17 20:04:32

问题1的答案:

如果没有完整的栅栏,就不会有JMM所要求的顺序一致性。

因此,X86提供了TSO。因此,下面的障碍是免费的LoadLoadStoreStore。唯一缺少的是StoreLoad。

装入具有获取语义

代码语言:javascript
复制
r1=X
[LoadLoad]
[LoadStore]

商店具有发布语义

代码语言:javascript
复制
[LoadStore]
[StoreStore]
Y=r2

如果你想做一个后跟加载的存储,你最终会得到这样的结果:

代码语言:javascript
复制
[LoadStore]
[StoreStore]
Y=r2
r1=X
[LoadLoad]
[LoadStore]

问题是加载和存储仍然可以重新排序,因此它不是顺序一致的;这对于Java内存模型是强制性的。他们唯一能防止这种情况发生的方法就是使用StoreLoad。最符合逻辑的地方是将其添加到写操作中,因为通常读操作比写操作更频繁。

这可以通过MFENCElock addl %(RSP),0来完成

问题2的答案:

putLong的问题是,不仅CPU可以重新排序指令,而且编译器可能会以导致指令重新排序的方式更改代码。

例如:如果你要在循环中执行putLong,编译器可能会决定将写出的内容从循环中拉出,并且该值将对其他线程不可见。如果你想要一个低开销的单一写入器性能计数器,你可能想看看putLongRelease/putLongOrdered(oldname)。这将阻止编译器执行上述操作。以及免费获得的X86上的发布语义。

但是很难给你的第二个问题一个万能的解决方案,因为这取决于你的目标是什么。

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

https://stackoverflow.com/questions/43460725

复制
相关文章

相似问题

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