一个块会打开另一个线程吗?

时间:2013-10-01 01:57:00

标签: ruby multithreading global-variables

此问题来自此代码段:

lambda do
  $SAFE = 2
  puts $SAFE
end .call

puts $SAFE

结果是:

2
0

$SAFE是一个全局变量,所以我无法理解这一点。我探索了一段时间,然后发现$SAFE是一个线程局部变量,而不是真正的全局变量。

好的,我能理解这一点:

k = Thread.new do
  $SAFE = 2
  puts $SAFE
end

k.run

1000000.times {}

puts $SAFE

但是等一下,该块会打开另一个线程来运行它吗?

1 个答案:

答案 0 :(得分:1)

不,块(procs,lambdas)不会在自己的线程中运行。这里的问题是Ruby在每个方法(和proc)调用周围保存并恢复$SAFE级别。如果您使用其他变量(例如$FOO)尝试此操作,则可获得预期结果:

> x = ->{ $FOO = 1; puts $FOO }.call; puts $FOO
1
1

您可以在rb_method_call中的proc.c中查看实施方式:

const int safe_level_to_run = 4 /*SAFE_LEVEL_MAX*/;
safe = rb_safe_level();
if (rb_safe_level() < safe_level_to_run) {
    rb_set_safe_level_force(safe_level_to_run);
}

// ...
// Invoke the block
// ...

if (safe >= 0)
  rb_set_safe_level_force(safe);

保存安全级别,如果小于4,则设置为4.然后调用该块,如果修改前的安全级别为> = 0,则恢复到之前的状态。您可以使用以下内容查看此操作:

> puts $SAFE; ->{ puts $SAFE; $SAFE = 1; puts $SAFE }.call; puts $SAFE
0
0
1
0

$SAFE在进入块时为0,并且块被执行,然后在块退出时恢复为0,尽管在块内被修改为1。