remove lingering reference to older module
[concurrent.git] / lib / concurrent / futures.rb
blob60dd1bc4dddd5becbdb5036699908dd3acb65343
2 # concurrent/futures - futures and lazy evaluation for Ruby
4 # Copyright (C) 2007  MenTaLguY <mental@rydia.net>
6 # This file is made available under the same terms as Ruby.
9 require 'thread'
10 begin
11   require 'fastthread'
12 rescue LoadError
13 end
14 require 'thwait'
16 module Concurrent
17 module Futures
19 module Future
20   extend Futures
21 end
23 class AsyncError < RuntimeError
24   attr_reader :reason
26   def initialize( reason, desc=nil )
27     super( desc )
28     @reason = reason
29   end
30 end
32 require 'concurrent/futures.so' # provides Thunk
34 def async( &block )
35   Thunk.new( Thread.new( &block ) )
36 end
37 alias spawn async
38 alias future async
40 def await( future )
41   Thunk.value future
42 end
44 def await_any( *futures )
45   threads = futures.map { |future| Thread.new { Futures::await future } }
46   begin
47     threads.index ThreadsWait.new( *threads ).wait_next
48   ensure
49     threads.each { |thread| thread.raise RuntimeError }
50   end
51 end
53 AlreadyFulfilledError = Class.new StandardError
55 class Promise
56   def initialize
57     @lock = Mutex.new
58     @ready = ConditionVariable.new
59   end
61   def future
62     @future ||= Thunk.new self
63   end
65   def fulfill( value )
66     @lock.synchronize do
67       if defined? @value
68         raise AlreadyFulfilledError, "promise already fulfilled"
69       end
70       @value = value
71       @ready.broadcast
72     end
73     self
74   end
76   def fulfilled?
77     @lock.synchronize { defined? @value }
78   end
80   def value
81     @lock.synchronize do
82       @ready.wait @lock until defined? @value
83       @value
84     end
85   end
87   def fail( ex )
88     @lock.synchronize do
89       @value = Thunk.new( Thread.new { raise ex } )
90     end
91     self
92   end
93 end
95 class Lazy
96   def initialize( &block )
97     @lock = Mutex.new
98   end
100   def value
101     @lock.synchronize do
102       if @block
103         @value = Thunk.new Thread.new( &block )
104         @block = nil
105       end
106       @value
107     end
108   end
110   def inspect
111     @lock.synchronize do
112       if @block
113         "#<Lazy pending #{ @block.inspect }>"
114       else
115         "#<Lazy requested #{ @value.inspect }>"
116       end
117     end
118   end
121 def lazy( &block )
122   Thunk.new( Lazy.new( &block ) )
125 class Ref
126   def initialize( value=nil )
127     @lock = Mutex.new
128     @value = value
129   end
131   def exchange( value )
132     @lock.synchronize do
133       result = @value
134       @value = value
135       result
136     end
137   end
139   def modify( &block )
140     @lock.synchronize do
141       value = @value
142       @value = Future.async { block.call value }
143     end
144   end