Friday, December 08, 2006

Pages 137-9: Mutual exclusion - Queues, Condition variables


Listen to this article.

Value: High

Level: Hard

Summary:
The Queue class, located in the thread library, implements a thread-safe queuing mechanism. Sometimes you need synchronization between threads based a condition: to do this you can use condition variables. A condition variable is a controlled way of communicating an event (or a condition) between two threads. One thread can wait on the condition, and the other can signal it.

Memo: If two threads are looping working on the same shared data, you're stuck: you'll need to use condition variables.

Example:
require 'monitor'
SONGS = [
'Blue Suede Shoes',
'Take Five',
'Bye Bye Love',
'Rock Around The Clock',
'Ruby Tuesday'
]
START_TIME = Time.now
def timestamp
(Time.now - START_TIME).to_i
end
# Wait for up to two minutes between customer requests
def get_customer_request
sleep(120 * rand)
song = SONGS.shift
puts "#{timestamp}: Requesting #{song}" if song
song
end
# Songs take between two and three minutes
def play(song)
puts "#{timestamp}: Playing #{song}"
sleep(120 + 60*rand)
end
ok_to_shutdown = false
# and here's our original code
playlist = []
playlist.extend(MonitorMixin)
plays_pending = playlist.new_cond
# Customer request thread  
customer = Thread.new do
loop do
req = get_customer_request
break unless req
playlist.synchronize do
playlist << req
plays_pending.signal
end
end
end
# Player thread
player = Thread.new do
loop do
song = nil
playlist.synchronize do
break if ok_to_shutdown && playlist.empty?
plays_pending.wait_while { playlist.empty? }
song = playlist.shift
end
break unless song
play(song)
end
end
customer.join
ok_to_shutdown = true
player.join


Reported errata (at 10/17/06 14:17:18 PDT): 1
  • #1942 is a minor typo on page 139.

Errata I found: 3
  • On page 137: duplicated word 'thread' in code comment.
  • On page 137: there's an incongruence: if the list gets emptied, there should be a thread for emptying it. Unfortunately the author talks about only two threads: one for adding to, one for reading the list.
  • On page 138: on line 26 of the code there's a comment states: "and here's our original code". It's not true, as the code is different from the one on page 137. Should be: "and here's a code similar to the one on page 137".

My suggestions to the author: 1 (3)
  • Totally rewrite this pages from scratch (see doubts below), or at least add these comments to the example code:
    • Line 9: add "# executed when the program starts".
    • Line 10: add "# chronologically increasing values".
    • Line 17: add "# if all the songs in SONGS have been played, song will be false".

Doubts: 9 (20)
My doubts all concern the example code on pages 138-9.
  • Line 2
    • What is SONGS ?
    • Is it an array of songs previously selected by the user ?
  • Line 13
    • What does this comment mean ? Why wait ?
  • Line 14
    • Why does get_customer_request method get the data from a premade array and not from the customer, as the method name suggests ?
  • Line 18
    • Why not use the return() method ?
    • Why does Ruby not raise an error in this case where the return() method is not used ?
  • Line 20
    • Does this comment mean that the shortest song has a duration of 120 seconds and the longest has a duration of 180 seconds ?
    • If yes, why should this information be useful ?
  • Line 23
    • Why let the program sleep instead of playing ?
    • Why does the play() method not play anything ?
  • Line 29
    • What is new_cond() ?
    • What does it do ?
    • Why is there no reference to it in the book's index ?
  • Line 37
    • What is signal() ?
    • What does it do ?
    • Why is there no refernce to it in the book's index ?
  • Line 45
    • What does this block do ?
  • Line 47
    • What's wait_while method ?
    • What does it do ?
    • Why is there no reference to it in the book's index ?

0 Comments:

Post a Comment

<< Home