You want your program to run two or more pieces of code in parallel.
Create a new thread by passing a code block into THRead.new. That block will run simultaneously with any code you write after the call to THRead.new.
The following code features two competing threads. One continually decrements a variable by one, while the main programs thread busily incrementing the same variable by three. The decrementing thread starts its work earlier, but the incrementing thread always wins in the end, because it increments the counter by a larger number:
x = 0
Thread.new do
while x < 5
x -= 1
puts "DEC: I decremented x to #{x}
"
end
puts "DEC: x is too high; I give up!
"
end
while x < 5
x += 3
puts "INC: I incremented x to #{x}
"
end
# DEC: I decremented x to -1
# DEC: I decremented x to -2
# DEC: I decremented x to -3
# DEC: I decremented x to -4
# INC: I incremented x to -1
# DEC: I decremented x to -2
# INC: I incremented x to 1
# DEC: I decremented x to 0
# INC: I incremented x to 3
# DEC: I decremented x to 2
# INC: I incremented x to 5
# DEC: x is too high; I give up!
x # => 5
A Ruby process starts out running only one thread: the main thread. When you call Thread#new, Ruby spawns another thread and starts running it alongside the main thread. The operating system divides CPU time among all the running processes, and the Ruby interpreter further divides its alotted CPU time among all of its threads.
The block you pass into THRead.new is a closure (see Recipe 7.4), so it has access to all the variables that were in scope at the time you instantiated the thread. This means that threads can share variables; as a result, you don need complex communication schemes the way you do to communicate between processes. However, it also means that your threads can step on each others toes unless you e careful to synchronize any shared objects. In the example above, the threads were designed to step on each others toes, providing head-to-head competition, but usually you don want that.
Once a threads execution reaches the end of its code block, the thread dies. If your main thread reaches the end of its code block, the process will exit and all your other threads will die prematurely. If you want your main thread to stall and wait for some other thread to finish, you can call Thread#join on the thread in question.
This code spawns a subthread to count to one million. Without the call to Thread#join, the counter only gets up to a couple hundred thousand before the process exits:
#!/usr/bin/ruby -w
# counter_thread.rb
counter = 0
counter_thread = Thread.new do
1.upto(1000000) { counter += 1; }
end
counter_thread.join unless ARGV[0]
puts "The counter was able to count up to #{counter}."
$ ./counter_thread.rb
The counter was able to count up to 1000000.
$ ./counter_thread.rb dont_call_join
The counter was able to count up to 172315.
You can get a list of the currently active thread objects with Thread.list:
Thread.new { sleep 10 }
Thread.new { x = 0; 10000000.times { x += 1 } }
Thread.new { sleep 100 }
Thread.list
# => [#, #,
# #, #]
Here, the two running threads are the main irb thread and the thread running the counter loop. The two sleeping threads are the ones currently running sleep calls.
Strings
Numbers
Date and Time
Arrays
Hashes
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Internet Services
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
User Interface
Extending Ruby with Other Languages
System Administration