Doing Two Things at Once with Threads

Table of contents:

Problem

You want your program to run two or more pieces of code in parallel.

Solution

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

Discussion

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



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net