【问题标题】:How does MRI parse the `||=` operator?MRI 如何解析 `||=` 运算符?
【发布时间】:2015-11-04 16:05:19
【问题描述】:

今天我试图向同事解释 ||= 在 MRI 中不是线程安全的。我想我会看一下 Ruby 源代码来尝试看看我是否可以指出 Ruby 调度程序可以切换线程上下文的位置,但是我在导航代码时遇到了问题。我希望更有经验的人可以指导我浏览被击中的文件。

到目前为止,我知道 Bison 使用 parse.y 并生成一个调用一些底层函数的 parse.c 文件。我看到 || 被解析为 tOROP 但是我对接下来发生的事情有点迷茫

还有像 Ripper 这样的工具,我可以使用它来简化这个过程吗? (如果有人能指出 Ripper 源代码的定义位置,那将会很有帮助)

【问题讨论】:

  • 就像x += 1 是非原子的一样。它需要读取、比较和(条件)赋值。 x ||= y 实际上是 x = x || yx = y unless (x),具体取决于您想要获得的具体程度。请注意,在这两种情况下,都需要在分配之前进行读取和比较(不是 false)。在那个间隙中,任何事情都可能发生。您可能想查看 MRI 表达该语句的字节码,以了解内部发生了什么。
  • MRI 的ruby 有一个--dump 选项。我认为您正在寻找 --dump yydebug,但您可能也对 parsetreeinsns 感兴趣。
  • @cremno 非常好!这绝对是一个很大的帮助ruby -e "@hello ||= 'hi'" --dump parsetree 看起来应该很有用
  • 我认为它可能在 MRI(但不是 JRuby)中是“意外”线程安全的。我明白你在问什么,我不知道 C 代码在哪里指向你,但我以前看过关于它的文章,也许你可以找到谷歌搜索。在 MRI 中,GIL 仅在某些点发布是对的,||= 可能会意外地成为线程安全的,但即使是这样,它也是一个实现细节,可能会发生变化,并且在其他解释器中并不安全。
  • 线程安全与解析器无关。别看那里了。 ||= 被重写为一系列操作(查看汇编代码)并且该序列可以被中断,在此期间另一个线程可以更改为条件读取的值。

标签: ruby


【解决方案1】:

忘记解析器,如果您查看代码in compile.c here,您将看到如何生成指令来处理分配或操作。每次调用 ADD_INSNL 都会发出一条指令。在第 4553 行,您会看到一个 if 条件,该条件在 LHS 的值被第 4546 行调用 COMPILE 宏发出的代码读取后测试它的值,以确定是否分配新的价值。在此期间,另一个线程可能会取代并更改读取的值,因此分配在不应该完成时完成(或未完成)。

关于如何创建 NODE_OP_ASGN_OR,请参见函数 new_op_assign_gen() 中从 parse.y 调用的对 NEW_OP_ASGN_OR(在 node.h 中定义)的调用。

希望行号不会很快更改,并使这些 URL 无效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-30
    • 2012-04-20
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 2011-05-20
    • 1970-01-01
    • 2021-09-07
    相关资源
    最近更新 更多