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
Errata I found: 3
My suggestions to the author: 1 (3)
Doubts: 9 (20)
My doubts all concern the example code on pages 138-9.
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