JMM 中的因果关系似乎是其中最令人困惑的部分。我有几个关于 JMM 因果关系和并发程序中允许的行为的问题。
据我了解,当前的 JMM 始终禁止因果循环。 (我说得对吗?)
现在,根据 JSR-133文档,第 24 页,图 16,我们有一个示例,其中:
最初x = y = 0
线程 1:
r3 = x;
if (r3 == 0)
x = 42;
r1 = x;
y = r1;
线程 2:
r2 = y;
x = r2;
直觉上,r1 = r2 = r3 = 42 似乎是不可能的。然而,它不仅被提及为可能,而且在 JMM 中也被“允许”。
对于这种可能性,文档中我看不懂的解释是:
A compiler could determine that the only values ever assigned to
xare 0 and 42. From that, the compiler could deduce that, at the point where we executer1 = x, either we had just performed a write of 42 tox, or we had just readxand seen the value 42. In either case, it would be legal for a read ofxto see the value 42. It could then changer1 = xtor1 = 42; this would allowy = r1to be transformed toy = 42and performed earlier, resulting in the behavior in question. In this case, the write toyis committed first.
我的问题是,它到底是一种什么样的编译器优化? (我对编译器一无所知。)由于 42 只是有条件地写入,当满足 if 语句时,编译器如何决定是否继续写入 x?
其次,即使编译器进行了这种推测性优化,并提交了 y = 42 和
然后最终使 r3 = 42 ,这不是违反因果循环吗,因为现在没有因果区别了?
事实上,在同一文档(第 15 页,图 7)中有一个示例,其中提到类似的因果循环是 Not Acceptable 。
那么为什么这个执行顺序在 JMM 中是合法的呢?
最佳答案
正如所解释的,曾经写入x 的唯一值是 0 和 42。线程 1:
r3 = x; // here we read either 0 or 42
if (r3 == 0)
x = 42;
// at this point x is definitely 42
r1 = x;
因此 JIT 编译器可以将 r1 = x 重写为 r1 = 42,进而 y = 42。重点是,线程 1 将总是、无条件地将 42 写入 y。 r3 变量实际上是多余的,可以从机器代码中完全删除。所以例子中的代码只是给出了从x到y的因果箭头的表象,但仔分割析发现,实际上并没有因果关系。令人惊讶的结果是可以提前提交对 y 的写入。
关于优化的一般说明:我认为您熟悉从主内存读取所涉及的性能损失。这就是 JIT 编译器一心想尽可能拒绝这样做的原因,在这个例子中,事实证明它实际上不需要读取 x 来知道要写入什么 y。
关于符号的一般说明:r1、r2、r3 是局部变量(它们可以在堆栈或 CPU 寄存器中); x, y 是共享变量(这些在主内存中)。如果不考虑这一点,示例将毫无意义。
关于java - 为什么在 Java 内存模型中允许这种行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13271649/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢