Last active
May 2, 2024 07:17
-
-
Save mrk21/b2a029d5601d4a1db9770f81f8b4127d to your computer and use it in GitHub Desktop.
Simple fork-safe proxy for Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ForkSafeProxy < BasicObject | |
class << self | |
def unwrap(instance) | |
instance.__send__(:__value__) | |
end | |
end | |
def initialize(&initializer) | |
@mutex = ::Thread::Mutex.new | |
@initializer = initializer | |
@value = nil | |
@pid = nil | |
end | |
def method_missing(method, *args, &block) | |
__value__.__send__(method, *args, &block) | |
end | |
private | |
def __value__ | |
return @value if @pid == $$ | |
@mutex.synchronize do | |
@value = @initializer.call | |
@pid = $$ | |
$stdout.puts "# initialized: #{$$}" | |
@value | |
end | |
end | |
end | |
class Runner | |
def initialize | |
@rand = ForkSafeProxy.new { Random.new } | |
@rand = ForkSafeProxy.unwrap(@rand) if ENV['UNWRAP'] == '1' | |
end | |
def run | |
puts_rand | |
child_pids = 3.times.map { fork { puts_rand } } | |
child_pids.each(&Process.method(:waitpid)) | |
end | |
def puts_rand | |
3.times { puts "#{$$}: #{@rand.rand(100)}" } | |
end | |
end | |
Runner.new.run | |
=begin | |
$ ruby fork_safe_proxy.rb | |
# initialized: 11488 | |
11488: 75 | |
11488: 50 | |
11488: 22 | |
# initialized: 11517 | |
11517: 55 | |
11517: 77 | |
11517: 49 | |
# initialized: 11518 | |
11518: 20 | |
11518: 65 | |
11518: 24 | |
# initialized: 11519 | |
11519: 90 | |
11519: 96 | |
11519: 67 | |
=end | |
=begin | |
$ UNWRAP=1 ruby fork_safe_proxy.rb | |
# initialized: 12750 | |
12750: 62 | |
12750: 22 | |
12750: 51 | |
12779: 51 | |
12779: 92 | |
12779: 70 | |
12780: 51 | |
12780: 92 | |
12780: 70 | |
12781: 51 | |
12781: 92 | |
12781: 70 | |
=end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment