gpt4 book ai didi

ruby - 多个线程调用同一个函数

转载 作者:数据小太阳 更新时间:2023-10-29 06:54:45 25 4
gpt4 key购买 nike

假设我们有多个线程都调用同一个函数:

def foo 
# do stuff ...
end

100.times do |i|
Thread.new do
foo
end
end

如果 foo 中当前有两个或多个线程,它们是否都在 foo 中共享相同的局部变量?

这涉及到我的第二个问题。线程是否有单独的栈帧,或者它们是否在单个进程中共享栈帧?具体来说,当多个线程各自调用 foo 并且在 foo 返回之前,堆栈上是否有多个 foo 副本,每个副本都有自己的局部变量,还是堆栈上只有一份 foo

最佳答案

是的,它们共享相同的变量。这是 Threads 的关键元素,在只读上下文中很好,但如果它们写入任何这些变量,则需要使用 Mutexsynchronize线程,因此在任何给定时间只有一个可以更改变量。有时他们可能会调用间接更改数据的方法,因此在决定是否需要同步之前,您需要充分了解系统。

关于你的第二个问题,如果我明白你在问什么,它们有单独的堆栈帧,但是它们仍然在内存中共享相同的数据。

澄清一下,在下面的示例中,局部变量 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 函数的范围之外访问,所以两个线程可能同时访问它。

这些“两个线程同时更改相同数据”的问题通过在更改变量的代码部分周围小心放置互斥体(锁)来解决。 Mutex 必须在创建线程之前创建,因为在 Mutex 的情况下,(按设计)两个线程访问同一个 Mutex 是至关重要的,以便知道它是否被锁定。

# 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 行时,它会尝试锁定互斥体。如果成功,它进入 block 并继续执行。 block 完成后,互斥锁将再次解锁。如果互斥体已经被锁定,线程会等待直到它再次空闲……实际上它就像一扇门,一次只有一个人可以穿过。

我希望这能解决问题。

关于ruby - 多个线程调用同一个函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10467070/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com