多个线程调用相同的功能
假设我们有多个线程都调用相同的函数:
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
函数的作用域之外访问,所以两个线程都可以同时访问它。
'两个线程同时改变相同数据'的这些问题可以通过在改变变量的代码部分周围使用仔细放置的Mutexes(锁)来解决。 必须在创建线程之前创建互斥锁,因为在互斥锁的情况下,两个线程访问相同的互斥锁(在设计上)至关重要,以便知道它是否被锁定。
# 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}}
在此之后,foo [:bar]可能包含值35,因为foobar的每次调用都会更改散列值foo中的值。
链接地址: http://www.djcxy.com/p/59167.html