Another Programming Ruby Question

B

Bharat Ruparel

This is from Chapter 11 titled "Threads and Processes" of Programming
Ruby book on page 139.

I am pasting the source code below:

# Sample code from Programing Ruby, page 131
$stderr.sync = $stdout.sync = true
Thread.abort_on_exception = true
threads = []
4.times do |number|
threads << Thread.new(number) do |i|
raise "Boom!" if i == 2
print "#{i}\n"
end
end
threads.each {|t| t.join }

Note that the page numbers in the downloaded code with the actual page
numbers do not match - probably due to two different Editions of the
book. Has not been a problem thus far.

When I run the code in SCITE, I get the following output:
ruby ex0318.rb
ex0318.rb:7: Boom! (RuntimeError)
from ex0318.rb:6:in `initialize'
from ex0318.rb:6:in `new'
from ex0318.rb:6
from ex0318.rb:5:in `times'
from ex0318.rb:5
Exit code: 1

Now the output shown in the book is different. It shows that a 0
followed by 1 are going to be output (on separate lines) before the
program hits the exception condition. I commented out the line which
says

$stderr.sync = $stdout.sync = true as follows:

# Sample code from Programing Ruby, page 131
# $stderr.sync = $stdout.sync = true
Thread.abort_on_exception = true
threads = []
4.times do |number|
threads << Thread.new(number) do |i|
raise "Boom!" if i == 2
print "#{i}\n"
end
end
threads.each {|t| t.join }

and re-ran the program.

This time I got the right output as below:
ruby ex0318.rb
0
1
ex0318.rb:7: Boom! (RuntimeError)
from ex0318.rb:6:in `initialize'
from ex0318.rb:6:in `new'
from ex0318.rb:6
from ex0318.rb:5:in `times'
from ex0318.rb:5
Exit code: 1

That set me thinking what does the line:
$stderr.sync = $stdout.sync = true
actually do?
I looked it up into the book and googled for it, but cannot find an
answer that makes sense. Would someone kindly explain in Ruby/Newby
terms? When to use it when not to use it etc? I know that this is
setting both standard error and standard output to the same channel.
What does the sync method do? What does it mean to set it to true? If
there are online resources that can be looked up for these kinds of
questions I will not bother you. But the online Ruby API almost mirrors
Dave Thomas's Programming Ruby book which I am working with anyway.
Thanks in advance for your time.
Bharat
 
B

Bharat Ruparel

Hello Lloyd,
I appreciate your time and detailed response.
It seems to me that I should see the opposite behavior to what I am
seeing based on the explanation that you provided. That is:
If setting sync to true causes no buffering then I should actually
observe the first two values (0 and 1) to be immediately output.
Instead, I see the exception messages as I show above. Since the
exception does not get raised until i reaches a value of 2, I should see
the 0 and 1 printed to the standard output and then I should see
exception being printed to standard error?
Bharat
 
M

Mauricio Fernandez

# Sample code from Programing Ruby, page 131
$stderr.sync = $stdout.sync = true
Thread.abort_on_exception = true
threads = []
4.times do |number|
threads << Thread.new(number) do |i|
raise "Boom!" if i == 2
print "#{i}\n"
end
end
threads.each {|t| t.join } [...]
When I run the code in SCITE, I get the following output:
ruby ex0318.rb
ex0318.rb:7: Boom! (RuntimeError)
from ex0318.rb:6:in `initialize'
from ex0318.rb:6:in `new'
from ex0318.rb:6
from ex0318.rb:5:in `times'
from ex0318.rb:5
Exit code: 1

The example assumes that the threads will be executed serially, and those with
i=0,1 will terminate before the third one raises a RuntimeError.

However, when you set $stdout.sync = true each time you printf whatever
Ruby will try to schedule another thread. In the above example, the two first
threads run until print "#{i}\n" and the third thread, which raises an
exception, is scheduled before the numbers are actually written to $stdout.

If you change the example so that the threads are rescheduled before the next
one is created, you'll get the expected output:

$ ruby
$stderr.sync = $stdout.sync = true
Thread.abort_on_exception = true
threads = []
4.times do |number|
threads << Thread.new(number) do |i|
raise "Boom!" if i == 2
print "#{i}\n"
end
sleep 0.01
end
threads.each {|t| t.join }
^D
0
1
-:6: Boom! (RuntimeError)
from -:5:in `initialize'
from -:5:in `new'
from -:5
from -:4:in `times'
from -:4

IO#sync does work the way it should, but the example is confusing.

--
Mauricio Fernandez - http://eigenclass.org - singular Ruby
** Latest postings **
Ruby, SEX and STDs: infectious practices
http://eigenclass.org/hiki.rb?ruby-warnings-SEX-and-stds
What's new in Ruby 1.9, Feb. 07 update
http://eigenclass.org/hiki.rb?Changes-in-Ruby-1.9-update-6
 
B

Bharat Ruparel

Thank you Mauricio. This makes perfect sense now.

On a separate note to all Ruby Newby persons: I am finding that
Programming Ruby or the PickAxe book almost should be your 2nd or 3rd
Ruby book. I am glad that I bought David Black's Ruby for Rails book
and went through it entirely before coming back to Programming Ruby
book. I have also bought Everyday Scripting based on my bookstore
browsing and am planning on going through it next. I will continue to
work through Dave Thomas's Programming Ruby book though. My advice to
everyone based on my experience is that don't get frustrated and ask
questions on this forum for clarifications. There are some very kind,
patient, and knowledgable people who are willing to spare their time and
facilitate the learning process.

Regards,
Bharat
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top