Skip to content

Commit 52c872c

Browse files
committed
Implement Stream using Atomic (rather than mutexes)
1 parent fbbbdc0 commit 52c872c

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

hamster.gemspec

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
2121
spec.test_files = Dir["test/**/*", "spec/**/*"]
2222
spec.require_paths = ["lib"]
2323

24+
spec.add_runtime_dependency "atomic", "~> 1.1"
2425
spec.add_development_dependency "bundler", "~> 1.3"
2526
spec.add_development_dependency "rspec", "~> 3.0"
2627
spec.add_development_dependency "rake", "~> 10.1"

lib/hamster/list.rb

+22-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
require "forwardable"
2-
require "thread"
2+
require "atomic"
33

44
require "hamster/core_ext/enumerable"
55
require "hamster/undefined"
@@ -686,9 +686,9 @@ class Stream
686686
include List
687687

688688
def initialize(&block)
689-
@block = block
690-
@lock = Mutex.new
691-
@size = nil
689+
@target = block
690+
@atomic = Atomic.new(0) # haven't yet run block
691+
@size = nil
692692
end
693693

694694
def_delegator :target, :head
@@ -705,22 +705,26 @@ def cached_size?
705705

706706
protected
707707

708-
def vivify
709-
@lock.synchronize do
710-
unless @block.nil?
711-
@target = @block.call
712-
@block = nil
708+
def target
709+
if @atomic.get == 2 # target already realized?
710+
@target
711+
else
712+
while true
713+
# try to "claim" the right to run the block which realizes target
714+
if @atomic.compare_and_swap(0,1) # full memory barrier here
715+
@target = @target.call
716+
@target = @target.target while @target.is_a?(Stream)
717+
@atomic.compare_and_swap(1,2) # another memory barrier
718+
return @target
719+
end
720+
# we failed to "claim" it, another thread must be running it
721+
if @atomic.get == 1 # another thread is running the block
722+
next # spin
723+
elsif @atomic.get == 2 # another thread finished the block
724+
return @target
725+
end
713726
end
714727
end
715-
@target
716-
end
717-
718-
private
719-
720-
def target
721-
list = vivify
722-
list = list.vivify while list.is_a?(Stream)
723-
list
724728
end
725729
end
726730

0 commit comments

Comments
 (0)