假设我们有多个线程调用所有相同功能:
def foo
# do stuff ...
end
100.times do |i|
Thread.new do
foo
end
end
如果两个或多个线程目前的内部foo
,难道他们每一股份在同一局部变量foo
?
这涉及到我的第二个问题。 在线程拥有独立的堆栈帧,或者他们共享一个进程中的栈帧? 具体来说,当多个线程调用每一个foo
之前foo
的回报,是有多个副本foo
在栈中,每个都有自己的局部变量,或者是有只有一个副本foo
在堆栈上?
是的,它们共享相同的变量。 这是线程的一个关键因素,是罚款只读语境,但如果他们写的任何这些变量,你需要使用一个Mutex
和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
线,它试图锁定互斥。 如果成功的话,它进入块并继续执行。 一旦块完成,互斥量被释放一次。 如果互斥已经锁定,该线程等待,直到它变成重获自由......有效就好像只有一个人可以一次走过一扇门。
我希望这将清除的东西了。
局部变量,所述方法中定义的,不被共享。 但它有可能对线程访问同一个对象的实例变量,如果它是在线程块的范围。
例如:
def foobar
puts "Foo is defined!" if defined?(foo)=='local-variable'
foo = 5
end
永远不会把字符串,如果所谓的由多个线程。
但下面需要同步互斥,因为比赛条件:
foo = {bar:5}
def foobar(value)
value[:bar]+=5
end
15.times{|i| Thread.new{foobar foo}}
在此之后,富[:巴]可能可能包含35值,因为foobar的的每一个电话,改变了哈希,FOO内的值。