我今天遇到了这段代码:
@thread ||= Thread.new do
# this thread should only spin up once
end
它被多个线程调用。我担心如果多个线程正在调用此代码,您可能会创建多个线程,因为 @thread
访问不同步。但是,有人告诉我,由于全局解释器锁,这不可能发生。我阅读了一些有关 Ruby 中线程的内容,似乎运行 Ruby 代码的各个线程可能会被其他线程抢占。如果是这种情况,你不能有这样的交错:
Thread A Thread B
======== ========
Read from @thread .
Thread.New .
[Thread A preempted] .
. Read from @thread
. Thread.New
. Write to @thread
Write to @thread
此外,由于对@thread 的访问不是同步的,因此对@thread
的写入是否保证对所有其他线程可见?我过去使用的其他语言的内存模型不能保证写入内存的可见性,除非您使用原子、互斥等同步对该内存的访问。
我仍在学习 Ruby,并且意识到要理解 Ruby 中的并发性还有很长的路要走。对此的任何帮助将不胜感激!
你需要一个互斥体。本质上,GIL 唯一保护你的是访问未初始化的内存。如果 Ruby 中的某些东西可以被明确定义而不是原子的,你不应该假设它是原子的。
一个简单的例子来说明你的例子排序是可能的。每次运行时我都会收到“double set”消息:
$global = nil
$thread = nil
threads = []
threads = Array.new(1000) do
Thread.new do
sleep 1
$thread ||= Thread.new do
if $global
warn "double set!"
else
$global = true
end
end
end
end
threads.each(&:join)
我是一名优秀的程序员,十分优秀!