Last active

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist
View gist:a6bd7b0440602e5333e1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
# Some examples for why the
#
# @obj ||= "some value"
#
# expression is threadsafe on MRI (should one be dumb enough to write
# such code)
#
# MRI will only preempt a Ruby thread when it is returning from a
# method call. If a code block contains no ruby method calls then
# then it will not be preempted. If it contains a single method
# call then the preemption point is predictable.
#
# This code:
#
# @obj ||= "some value"
#
# expands to:
#
# if @obj
# @obj = "some value"
# end
#
# and for this to be unsafe it should contain two method calls. There
# are none or one depending on how you count it.
#
# Now if I were to change the code to something like this
#
# @obj ||= Whatever.new
#
# then now there is a function call between the CHECK and SET
# operations and it is no longer thread safe.
#
#
# Regardless of how safe the original code was, the best thing to do
# is avoiding shared state when working with threads:
#
# Don't communicate by sharing memory; share memory by communicating
# (Go Programming Language).
 
 
class DoesNotPreemptWithoutMethodCalls
def run
@whatever = nil
@non_nil_count = 0
@thread_count = 1_000
@thread_count.times.map do
Thread.new do
if @whatever != nil
@non_nil_count += 1
end
@whatever ||= 1 # ??? Thread safe ???
end
end.each(&:join)
 
if @thread_count == @non_nil_count + 1
puts "OK"
else
puts "BUM: Preempted without a method call!"
end
end
end
DoesNotPreemptWithoutMethodCalls.new.run
 
 
class HaveSomeMethodcallsForPreemtion
def count_non_nils
if @whatever != nil
@non_nil_count += 1
end
# may preempt here
end
 
def run
@whatever = nil
@non_nil_count = 0
@thread_count = 1_000
@thread_count.times.map do
Thread.new do
count_non_nils # may be preempted here
@whatever ||= 1 # but not here
end
end.each(&:join)
 
if @thread_count == @non_nil_count + 1
puts "2 - OK"
else
puts "2 - BUM: Preempted without a method call!"
end
end
end
HaveSomeMethodcallsForPreemtion.new.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.