# Testing Thread Safety in IRB

Hello I wrote this solution to a practice problem. I have received some feedback mentioning that it is not thread safe. Is there a way to test for this in IRB?

“If you spin up several threads and have the same Beer Song sing
different sets of verses at the same time, they’ll get in each-other’s
way. Same thing with a Singer.”

``````class Beer

def sing(start_verse, end_verse = 0)
@start_verse = start_verse
@end_verse = end_verse

requested_verses
end

def verse(verse_number)
singer = Singer.new
singer.recall_verse(verse_number)
end

private

def requested_verses
requested_verse_numbers = start_verse.downto(end_verse)
requested_verses = ""

requested_verse_numbers.each do |requested_verse_number|
requested_verses << verse(requested_verse_number) + "\n"
end
requested_verses
end

end

class Singer
attr_accessor :bottles_of_beer, :verse_number

def initialize
@bottles_of_beer = nil
end

def recall_verse(verse_number)
@bottles_of_beer = verse_number
"#{dynamic_phrase_1} of beer on the wall, #{dynamic_phrase_2} of beer.\n#{dynamic_phrase_3}, #{dynamic_phrase_4} of beer on the wall.\n"
end

private

def dynamic_phrase_1
if zero_bottles?
"No more bottles"
else
"#{bottles_of_beer} #{bottle_s}"
end
end

def dynamic_phrase_2
if zero_bottles?
"no more #{bottle_s}"
else
"#{bottles_of_beer} #{bottle_s}"
end
end

def dynamic_phrase_3
one_it = 'one'

if zero_bottles?
'Go to the store and buy some more'
else
if one_bottle?
one_it = 'it'
end
"Take #{one_it} down and pass it around"
end
end

def dynamic_phrase_4
if one_bottle?
"no more bottles"
elsif zero_bottles?
"99 #{bottle_s}"
else
@bottles_of_beer -= 1
"#{bottles_of_beer} #{bottle_s}"
end
end

# This returns the correct plural or singular usage of bottle
def bottle_s
if bottles_of_beer > 1 || bottles_of_beer == 0
'bottles'
elsif one_bottle?
'bottle'
end
end

def one_bottle?
bottles_of_beer == 1
end

def two_bottles?
bottles_of_beer == 2
end

def zero_bottles?
bottles_of_beer == 0
end

end``````

Most threading problems happen when Ruby switches threads at an inconvenient moment, leaving things in an inconsistent state. In your case, switching thread in the middle of any of the `dynamic_phrase` methods to another thread that called `recall_verse` on the same `Singer` would cause problems: When Ruby switched back to the original thread the value of `@bottles_of_beer` would have changed and the rest of the verse would be inconsistent.

The reason threading bugs are so tricky is that they are unpredictable. There are many different ways to interleave the code between multiple threads, and most of them will work just fine. This makes it very difficult to write a simple test (in IRB or otherwise) to catch them: You could run the code multiple times and never see the bug.

You might find this article by Jessie Storimer helpful in understanding the potential problems: Does the GIL Make Your Ruby Code Thread-Safe?

I know it doesn’t answer your question directly, but I hope it’s helpful all the same.