0

这个问题来自这个代码片段:

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

但是等等,block会打开另一个线程来运行吗?

4

1 回答 1

1

不,块(procs、lambdas)不在它们自己的线程中运行。这里的问题是 Ruby 保存和恢复$SAFE每个方法(和 proc)调用的级别。如果您尝试使用另一个变量,例如$FOO,您会得到预期的结果:

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

你可以看到这是在哪里实现rb_method_callproc.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。

于 2013-10-01T19:31:27.613 回答