Doing Two Things at Once with Threads

Table of contents:


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}
	 puts "DEC: x is too high; I give up!

	while x < 5
	 x += 3
	 puts "INC: I incremented x to #{x}
	# 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; }

	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 }
	# => [#, #,
	# #, #]

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.



Date and Time



Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming


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

Similar book on Amazon

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