是的,它们共享相同的变量。这是线程的关键元素,在只读上下文中很好,但是如果它们写入任何这些变量,则需要使用Mutex
and synchronize
线程,因此在任何给定时间只有一个可以更改变量。有时他们可能会调用间接更改数据的方法,因此在决定是否需要同步之前,您需要完全了解系统。
至于你的第二个问题,如果我明白你在问什么,他们有单独的堆栈框架,but它们仍然在内存中共享相同的数据。
在下面的示例中,澄清了局部变量zip
is由多个线程共享,因为它是在当前作用域中定义的(线程不会更改作用域,它们只是在当前作用域中启动一个单独的并行执行线程)。
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
method.
然而,下面的代码是危险的:
@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
函数,因此两个线程可能同时访问它。
通过在更改变量的代码部分周围仔细放置互斥体(锁),可以解决“两个线程同时更改相同数据”的问题。互斥体must被创造before创建线程,因为在互斥体的情况下,两个线程访问同一个互斥体(根据设计)至关重要,以便知道它是否被锁定。
# 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
行,它尝试锁定互斥锁。如果成功,则进入该块并继续执行。一旦块完成,互斥体将再次解锁。如果互斥量已经被锁定,则线程会等待,直到它再次空闲......实际上,它就像一扇每次只有一个人可以穿过的门。
我希望这能解决问题。