Ruby Programming/Reference/Objects/Thread

Thread

edit

The Thread class in Ruby is a wrapper/helper for manipulating threads (starting them, checking for status, storing thread local variables).

Here is a good tutorial.

Note that with MRI 1.8, Ruby used "green threads" (pseudo threads--really single threaded). With 1.9, MRI uses "native threads with a global interpeter lock" so "typically single threaded". Jruby uses true concurrent threads. IronRuby uses true concurrent threads. Rubinius has threading currently like MRI 1.9. See here for a good background.

Because 1.8 uses green threads this means that, for windows, any "C" call (like gets, puts, etc.) will block all other threads until it returns. The scheduler can only switch from thread to thread when it is running ruby code. However, you can run sub processes in a thread and it will work, and you can run select and it will still be able to switch among threads. For Linux this means that you can select on $stdin and thus not block for input. For windows, though, you're really stuck. Any keyboard input will block all other threads. With 1.9 this isn't as much of a problem because of the use of native threads (the thread doing the IO call releases its hold on the GIL until the IO call returns). You can use Jruby[1] for a non blocking 1.8.

With 1.9 you can get "around" the global thread lock by wrapping a C call in rb_thread_blocking_region (this will basically allow that thread to "go off and do its thing" while the other ruby threads still operate, one at a time. When the method returns, it will enter ruby land again and be one of the "globally locked" (one at a time) threads).

Thread local variables

edit

If you want to start a thread with a specific parameter that is unique to that thread, you could use Thread.current

Thread.new { 
  puts Thread.current # unique!
}

Or you can start it with a parameter, like

th = Thread.new(33) {|parameter|
  thread_unique_parameter = parameter
}

This avoids concurrency issues when starting threads, for example

# BROKEN
for x in [1,2,3] do
 Thread.new {
   puts x # probably always outputs 3 because x's value changes due to the outside scope
 }
end


Joining on multiple threads

edit

For this one, use the ThreadsWait class.

require 'thwait'
ThreadsWait.join_all(th1, th2, th3) do |th_that_just_exited| # could also call it like join_all([th1, th2, ...])
  puts 'thread just exited', th_that_just_exited
end
# at this point they will all be done

Controlling Concurrency

edit

See the Mutex class for how to control interaction between threads.

  1. http://betterlogic.com/roger/?p=2930