简体   繁体   English

Ruby线程安全的线程创建

[英]Ruby thread safe thread creation

I came across this bit of code today: 我今天遇到了这段代码:

@thread ||= Thread.new do
  # this thread should only spin up once
end

It is being called by multiple threads. 它被多个线程调用。 I was worried that if multiple threads are calling this code that you could have multiple threads created since @thread access is not synchronized. 我担心如果多个线程正在调用此代码,由于@thread访问未同步,您可能会创建多个线程。 However, I was told that this could not happen because of the Global Interpreter Lock. 但是,有人告诉我,由于全局解释器锁定,这不可能发生。 I did a little bit of reading about threads in Ruby and it seems like individual threads that are running Ruby code can get preempted by other threads. 我做了一些关于Ruby中线程的阅读,看来运行Ruby代码的单个线程可能会被其他线程抢占。 If this is the case, couldn't you have an interleaving like this: 如果是这种情况,您是否不能像这样进行交错:

Thread A             Thread B
========             ========
Read from @thread    .
Thread.New           .
[Thread A preempted] .
.                    Read from @thread
.                    Thread.New
.                    Write to @thread
Write to @thread

Additionally, since access to @thread is not synchronized are writes to @thread guaranteed to be visible to all other threads? 另外,由于对@thread的访问未同步, @thread保证对@thread写入对所有其他线程可见? The memory models of other languages I've used in the past do not guarantee visibility of writes to memory unless you synchronize access to that memory using atomics, mutexes, etc. 除非您使用原子,互斥锁等同步访问该内存,否则我过去使用的其他语言的内存模型不能保证对内存写入的可见性。

I'm still learning Ruby and realize I have a long way to go to understanding concurrency in Ruby. 我仍在学习Ruby,并且意识到要理解Ruby中的并发性还有很长的路要走。 Any help on this would be super appreciated! 任何帮助,将不胜感激!

You need a mutex. 您需要一个互斥锁。 Essentially the only thing the GIL protects you from is accessing uninitialized memory. 本质上,GIL保护您免受攻击的唯一一件事就是访问未初始化的内存。 If something in Ruby could be well-defined without being atomic, you should not assume it is atomic. 如果Ruby中的某些东西可以被很好地定义而不是原子的,那么您不应该假定它是原子的。

A simple example to show that your example ordering is possible. 一个简单的示例说明您可以进行示例排序。 I get the "double set" message every time I run it: 每次运行时,都会收到“双重设置”消息:

$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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM