Ruby STM: Round the Third
Previously on this blog:
Here’s what’s I’ve implemented since the last couple posts:
STM::Variable, a trivial transactional container for a single value- a replacement API for
STM#or_else - deadlock detection
- blocking retries
Specifically, STM#or_else has been replaced by STM.retries?, a class
method which takes a block and returns true or false depending on whether
the given sub-transaction retries. I’ve also added TrueClass#then_try and
FalseClass#then_try, which yield to the given block and do nothing,
respectively. Given this, we can write a new Ruby version of
Audrey’s sample script:
require 'stm'
a = STM::Variable.new 0
still_running = STM::Variable.new 2
t1 = Thread.new {
puts "Thread 1 started"
STM.atomically {
STM.retry until a[] > 5
a[] = -1000
still_running[] -= 1
}
puts "Thread 1 finished: a is >5 and reset to -1000"
}
t2 = Thread.new {
puts "Thread 2 started"
STM.atomically {
STM.retries? {
STM.retry until a[] > 100
}.then_try {
STM.retry until a[] < -100
}
still_running[] -= 1
}
puts "Thread 2 finished: a is now < -100"
}
while still_running[].nonzero?
puts STM.atomically { saved = a[] ; a += 1 ; saved }
sleep 1
end
t1.join
t2.join
Just like its Perl 6 counterpart (sigils aside), it outputs:
Thread 1 started
Thread 2 started
0
1
2
3
4
5
Thread 1 finished: a is >5 and reset to -1000
Thread 2 finished: a is now < -100