We don’t like when things collide.
Photo by szlea
But what if we need them to? What if we want to ensure that should a collision between threads happen, things will not go out of hand?
This is remarkably easy to do. Let’s pretend we want
$somevar to be thread-safe:
require 'test/unit' class Collision < Test::Unit::TestCase def test_that_fails a = Thread.new do 5.times do | t | $somevar = true sleep(rand(10)/200.0) assert_equal true, $somevar, "Somevar should keep the state true" end end b = Thread.new do 5.times do | t | $somevar = false sleep(rand(10)/200.0) assert_equal false, $somevar, "Somevar should keep the state false" end end ensure a.join; b.join end end
Fail. Global variables are never thread-safe, neither are class variables and module attributes.
The .times call is somewhat cargo cult programming, because this fails for me on first iteration. Replace the $somevar with your getter and setter and you should see negative results immediately.
How does it work? Simple - we are spinning off two threads, they set the variable and wait in
Kernel#sleep for the other thread to arrive and do it’s own assignment. It ensures that between the variable assignment and the assertion there’s just enough time for another thread to set the new value for the variable.