x86 上 Java 侵入性最小的编译屏障

2024-02-17

如果我有一个 Java 进程通过共享 ByteBuffer 或类似的方式与其他进程交互,那么 C/C++ 中的编译器屏障的侵入性最小的等效项是什么?不需要可移植性 - 我对 x86 特别感兴趣。

例如,我有 2 个进程根据伪代码读取和写入内存区域:

p1:
    i = 0
    while true:
      A = 0
      //Write to B
      A = ++i

p2:
    a1 = A
    //Read from B
    a2 = A

    if a1 == a2 and a1 != 0:
      //Read was valid

由于 x86 上严格的内存排序(加载到单独的位置不重新排序,读取到单独的位置不重新排序),这不需要 C++ 中的任何内存屏障,只需要每次写入之间和每次读取之间的编译屏障(即 asm 易失性)。

如何以最便宜的方式在 Java 中实现相同的排序约束。有什么比写入易失性的侵入性更小吗?


sun.misc.Unsafe.putOrdered 应该做你想做的事 - 一个存储,其锁在 x86 上由 易失性隐含。我相信编译器不会围绕它移动指令。

这与 AtomicInteger 等上的lazySet 相同,但不能直接与 ByteBuffer 一起使用。

Unlike volatile or the AtomicThings类,该方法适用于您使用它的特定写入,而不是成员的定义,因此使用它并不意味着任何读取。

看起来你正在尝试实现类似的东西seqlock http://en.wikipedia.org/wiki/Seqlock- 这意味着您需要避免在版本计数器的读取之间重新排序,A,以及数据本身的读/写。普通的 int 并不能解决问题——因为 JIT 可能会做各种顽皮的事情。我的建议是为您的计数器使用 volatile int ,然后将其写入putOrdered。这样,您就不必为易失性写入(通常是十几个周期或更多)付出代价,同时获得易失性读取所隐含的编译器屏障(并且这些读取的硬件屏障是无操作的,从而使它们更快) )。

话虽如此,我认为你处于灰色地带,因为lazySet不是正式内存模型的一部分,并且不能完全符合发生前推理,因此您需要更深入地了解实际的 JIT 和硬件实现,看看是否可以通过这种方式组合事物。

最后,即使有易失性的读取和写入(忽略lazySet),我认为从java内存模型的角度来看你的seqlock并不合理,因为易失性写入仅在另一个线程上的写入和稍后的读取之间以及写入线程中的早期操作之间建立一个发生之前,但是不在写入线程上的读取和写入操作之间。换句话说,它是单向围栏,而不是双向围栏。我相信,即使读取 A == N 两次,读取线程也可以看到版本 N+1 中对共享区域的写入。

评论中的澄清:

挥发性只建立了一个单向障碍。它与 WinTel 在某些 API 中使用的获取/释放语义非常相似。例如,假设 A、Bv 和 C 最初全部为零:

Thread 1:
A = 1;   // 1
Bv = 1;  // 2
C = 1;   // 3

Thread 2:

int c = C;  // 4
int b = Bv; // 5
int a = A;  // 6

这里,只有 Bv 是不稳定的。这两个线程正在执行与 seqlock 写入器和读取器概念类似的操作 - 线程 1 按一个顺序写入一些内容,线程 2 以相反的顺序读取相同的内容,并尝试从中推理出顺序。

如果线程二有 b == 1,则 a == 1 总是,因为 1 发生在 2 之前(程序顺序),而 5 发生在 6 之前(程序顺序),最关键的是 2 发生在 5 之前,因为 5 读取写入的值at 2. 因此,通过这种方式,Bv 的写入和读取就像栅栏一样。上面 (2) 的东西不能“移动到下面”(2),并且下面的东西 (5) 不能“移动到上面”5。请注意,我只限制每个线程直接在一个线程中移动,但不能同时限制两者的移动,这将我们带到下一个例子:

与上述相同,您可能会假设如果 a == 0,则 c == 0 也一样,因为 C 写在 a 之后,读取在 a 之前。然而,挥发物并不能保证这一点。特别是,上面发生的推理不会阻止 (3) 被移动到 (2) 之上(如线程 2 所观察到的),也不会阻止 (4) 被推到 (5) 之下。

Update:

让我们具体看看你的例子。

我相信可能发生的是这样的,展开 p1 中发生的写循环。

p1:

i = 0
A = 0
// (p1-1) write data1 to B
A = ++i;  // (p1-2) 1 assigned to A

A=0  // (p1-3)
// (p1-4) write data2 to B
A = ++i;  // (p1-5) 2 assigned to A

p2:

a1 = A // (p2-1)
//Read from B // (p2-2)
a2 = A // (p2-3)

if a1 == a2 and a1 != 0:

假设 p2 看到 a1 和 a2 均为 1。这意味着 p2-1 和 p1-2(以及扩展 p1-1)之间以及 p2-3 和 p1-2 之间都有一个发生。然而,p2 和 p1-4 中的任何内容之间都有发生之前的情况。所以事实上,我相信在 p2-2 处读取 B 可以观察到在 p1-4 处的第二次(可能部分完成)读取,它可以“移动到”p1-2 和 p1-3 处的易失性写入之上。

这很有趣,我认为你可能会仅仅就这一点提出一个新问题 - 忘记更快的障碍 - 即使对于 挥发性 ,这是否也有效?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

x86 上 Java 侵入性最小的编译屏障 的相关文章

随机推荐

  • 阻止 Visual Studio 自动更改 IIS 虚拟目录的物理路径?

    我有一个 Visual Studio 解决方案 其中包含一个 Web 应用程序项目 以及其他一些项目 Visual Studio 典型 设置似乎坚持认为二进制文件的输出目录位于项目源目录的根目录中 特别是 每次打开Web应用程序项目时 Vi
  • iOS 10.1 启动应用程序时出现警告

    为什么应用程序收到此警报以及如何解决此问题 AppName 可能会减慢您的 iPhone 该应用程序的开发人员需要更新它以提高其兼容性 我已经浏览过这个链接 iOS 10 1 模拟器显示 应用程序可能会减慢您的 iPhone 速度 http
  • 获取使用 calc 等表达式的 CSS 变量的计算值

    在 JavaScript 中 您可以使用以下命令获取 CSS 变量的值getPropertyValue property https developer mozilla org en US docs Web API CSSStyleDecl
  • Sinatra/Rack 的一个非常简单的身份验证方案是什么

    我正忙于将一个非常小的 Web 应用程序从 ASP NET MVC 2 移植到 Ruby Sinatra 在 MVC 应用程序中 当根据数据库正确验证用户登录时 FormsAuthentication SetAuthCookie 用于设置持
  • 如何使用接口实现松耦合?

    我似乎不明白接口如何实现松耦合的概念 您可能会发现这个问题与其他问题重复 但我已经阅读了许多与该主题相关的答案 但没有找到令人满意的解释 下面是许多开发人员实现松散耦合的示例 interface shape public function
  • 如何禁用 Django allauth 中的中间注销页面

    How to disable the intermediate signout page from django allauth When the user clicks on the signout link on my site I w
  • 使用“copy”属性来维护不可变的 NSString

    我对 iOS 开发和 Objective C 编程非常陌生 我一直在应用程序开发库上做练习 这是我正在尝试理解的当前练习 3 测试如果您将可变字符串设置为该人的名字 然后在调用修改后的 sayHello 方法之前更改该字符串 会发生什么情况
  • SwiftUI 中联系人应用程序中的联系人列表

    您好 我正在尝试构建一个列出所有联系人的界面 就像Contacts and Phone应用程序具有相同的UI 到目前为止我所尝试的如下 基本上我尝试实施CNContactPickerViewController from ContactsU
  • 如何向 THREE.BufferGeometry 添加面?

    我以编程方式创建了一个简单的网格 var CreateSimpleMesh new function var xy maxX 7 maxY 10 river 0 5 0 4 1 3 2 2 3 2 4 1 5 1 6 0 grassGeom
  • 如何将当前git分支的名称放入shell脚本中的变量中? [复制]

    这个问题在这里已经有答案了 我是 shell 脚本新手 无法弄清楚这一点 如果您不熟悉 命令 gitbranch 返回类似的内容 develop master 其中星号标记当前签出的分支 当我在终端中运行以下命令时 git branch g
  • JavaFX 树视图不显示任何项目

    我尝试在我的 JavaFX 应用程序中实现 TreeView 但不幸的是没有显示任何项目 但我找不到问题 我搜索了一些例子并像他们一样做了 我将 TreeView 控件放入 SceneBuilder 中的 FXML 文件中 并选择生成的 C
  • Java:将(长)对象转换为双精度的多种方法

    我有一个Object obj我知道实际上是一个long 在一些数学代码中我需要它作为double 直接将其转换为双倍安全吗 double x double obj 或者我应该先将其转换为 long 然后再转换为 double double
  • 具有多行的 NSTextFieldCell

    我需要显示一个包含多行且每行格式不同的 NSTextFieldCell 像这样的事情 Line 1 Title2号线 描述 我对 NSTextFieldCell 进行了子类化 但我不知道如何继续使用它 有任何想法吗 首先 你不have子类化
  • 将连接限制为一行

    我有以下查询 SELECT sum select count as itemCount SalesOrderItems price as amount rma as creditType Clients company as client
  • C在short和int之间转换的规则是什么?

    当使用 C 在 Short 和 int 之间进行转换时 我感到很困惑 我假设short是16位 int是32位 我用下面的代码进行了测试 unsigned short a 0xFFFF signed short b 0xFFFF unsig
  • 在 Win32 C++ 中创建 GUI

    我正在开发我的第一个 Windows 桌面应用程序 并且正在尝试找出创建该程序的 GUI 的最佳方法 我知道 我知道 考虑到有关该主题的数据量 我觉得问这个问题很愚蠢 然而 大多数答案似乎已经过时 我不确定它们是否适合我的特定项目 另外 W
  • 什么是测试中的软件故障? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我正在上软件测试的研究生课程 我们花了一整堂课来讨论故障 错误和故障之间的区别 我对测试中软件故障的定义不满意 你的定义是什么 您可能对此感兴趣
  • 何时使用 Vanilla JavaScript 与 jQuery?

    我注意到 在监视 尝试回答常见 jQuery 问题时 有一些使用 javascript 而不是 jQuery 的做法 实际上使您能够少写多做 同样的数量 并且还可能产生性能优势 一个具体的例子 this vs this 在引用被单击对象 i
  • Visual C++ 似乎对类的 POD 成员进行了零初始化,但它不应该这样做

    我有一堂这样的课 class TestClass public TestClass Note I wish not to initialize rawMemory for whatever reason int rawMemory 32 i
  • x86 上 Java 侵入性最小的编译屏障

    如果我有一个 Java 进程通过共享 ByteBuffer 或类似的方式与其他进程交互 那么 C C 中的编译器屏障的侵入性最小的等效项是什么 不需要可移植性 我对 x86 特别感兴趣 例如 我有 2 个进程根据伪代码读取和写入内存区域 p