是的,它们共享相同的变量。这是线程的关键元素,在只读上下文中很好,但是如果它们写入任何这些变量,则需要使用 aMutex
和synchronize
线程,因此在任何给定时间只有一个可以更改变量。有时他们可能会调用间接更改数据的方法,因此在决定是否需要同步之前,您需要完全了解系统。
至于你的第二个问题,如果我理解你的问题,它们有单独的堆栈帧,但它们仍然在内存中共享相同的数据。
澄清一下,在以下示例中,局部变量zip
由多个线程共享,因为它是在当前范围内定义的(线程不会更改范围,它们只是在当前范围内启动一个单独的并行执行线程)。
zip = 42
t = Thread.new do
zip += 1
end
t.join
puts zip # => 43
这里的加入拯救了我,但显然,如果我把它留在那里,线程根本没有意义。如果我要执行以下操作会很危险:
zip = 42
t = Thread.new do
zip += 1
end
zip += 1
puts zip # => either 43 or 44, who knows?
那是因为你基本上有两个线程都试图同时修改zip
。当您访问网络资源或递增数字等时,这会变得很明显,如上所述。
然而,在下面的例子中,局部变量zip
是在一个全新的范围内创建的,所以两个线程实际上并没有同时写入同一个变量:
def foo
zip = 42
zip += 1 # => 43, in both threads
end
Thread.new do
foo
end
foo
有两个并行堆栈被管理,每个堆栈在方法中都有自己的局部变量foo
。
但是,以下代码很危险:
@zip = 42 # somewhere else
def foo
@zip += 1
end
Thread.new do
foo
end
foo
puts @zip # => either 43 or 44, who knows?
这是因为实例变量@zip
可以在函数范围之外访问foo
,所以两个线程可能同时访问它。
“两个线程同时更改相同数据”的这些问题通过在更改变量的代码部分周围使用精心放置的互斥锁(锁)来解决。必须在创建线程之前创建互斥锁,因为在互斥锁的情况下,两个线程访问同一个互斥锁(根据设计)至关重要,以便知道它是否被锁定。
# somewhere else...
@mutex = Mutex.new
@zip = 42
def foo
@mutex.synchronize do
@foo += 1
end
end
Thread.new do
foo
end
foo
puts @zip # => 44, for sure!
如果当执行流程到达该Mutex#synchronize
行时,它会尝试锁定互斥锁。如果成功,则进入块并继续执行。块完成后,互斥锁将再次解锁。如果互斥锁已经被锁定,线程会一直等待,直到它再次空闲……实际上它就像一扇门,一次只有一个人可以穿过。
我希望这能解决问题。