concurrent-ruby 0.9.2-java → 1.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -1
- data/README.md +86 -120
- data/lib/concurrent.rb +14 -5
- data/lib/concurrent/agent.rb +587 -0
- data/lib/concurrent/array.rb +39 -0
- data/lib/concurrent/async.rb +296 -149
- data/lib/concurrent/atom.rb +135 -45
- data/lib/concurrent/atomic/abstract_thread_local_var.rb +38 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +83 -118
- data/lib/concurrent/atomic/atomic_fixnum.rb +101 -163
- data/lib/concurrent/atomic/atomic_reference.rb +1 -8
- data/lib/concurrent/atomic/count_down_latch.rb +62 -103
- data/lib/concurrent/atomic/cyclic_barrier.rb +3 -1
- data/lib/concurrent/atomic/event.rb +1 -1
- data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
- data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
- data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
- data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
- data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
- data/lib/concurrent/atomic/read_write_lock.rb +5 -4
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
- data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
- data/lib/concurrent/atomic/semaphore.rb +84 -178
- data/lib/concurrent/atomic/thread_local_var.rb +65 -294
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -0
- data/lib/concurrent/atomic_reference/jruby.rb +1 -1
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
- data/lib/concurrent/atomic_reference/ruby.rb +1 -1
- data/lib/concurrent/atomics.rb +7 -37
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +7 -15
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +7 -15
- data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
- data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +144 -0
- data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
- data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
- data/lib/concurrent/concern/dereferenceable.rb +9 -24
- data/lib/concurrent/concern/logging.rb +1 -1
- data/lib/concurrent/concern/obligation.rb +11 -20
- data/lib/concurrent/concern/observable.rb +38 -13
- data/lib/concurrent/configuration.rb +23 -152
- data/lib/concurrent/constants.rb +8 -0
- data/lib/concurrent/delay.rb +14 -12
- data/lib/concurrent/exchanger.rb +339 -41
- data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
- data/lib/concurrent/executor/executor_service.rb +23 -359
- data/lib/concurrent/executor/immediate_executor.rb +3 -2
- data/lib/concurrent/executor/java_executor_service.rb +100 -0
- data/lib/concurrent/executor/java_single_thread_executor.rb +3 -3
- data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
- data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +10 -66
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +25 -22
- data/lib/concurrent/executor/safe_task_executor.rb +6 -7
- data/lib/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent/executor/serialized_execution.rb +10 -33
- data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent/executor/simple_executor_service.rb +1 -10
- data/lib/concurrent/executor/single_thread_executor.rb +20 -10
- data/lib/concurrent/executor/timer_set.rb +8 -10
- data/lib/concurrent/executors.rb +12 -2
- data/lib/concurrent/future.rb +6 -4
- data/lib/concurrent/hash.rb +35 -0
- data/lib/concurrent/immutable_struct.rb +5 -1
- data/lib/concurrent/ivar.rb +12 -16
- data/lib/concurrent/lazy_register.rb +11 -8
- data/lib/concurrent/map.rb +180 -0
- data/lib/concurrent/maybe.rb +6 -3
- data/lib/concurrent/mutable_struct.rb +7 -6
- data/lib/concurrent/mvar.rb +26 -2
- data/lib/concurrent/{executor/executor.rb → options.rb} +5 -29
- data/lib/concurrent/promise.rb +7 -5
- data/lib/concurrent/scheduled_task.rb +13 -71
- data/lib/concurrent/settable_struct.rb +5 -4
- data/lib/concurrent/synchronization.rb +15 -3
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent/synchronization/abstract_object.rb +7 -146
- data/lib/concurrent/synchronization/abstract_struct.rb +2 -3
- data/lib/concurrent/synchronization/condition.rb +6 -4
- data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent/synchronization/jruby_object.rb +44 -0
- data/lib/concurrent/synchronization/lock.rb +3 -2
- data/lib/concurrent/synchronization/lockable_object.rb +72 -0
- data/lib/concurrent/synchronization/mri_lockable_object.rb +71 -0
- data/lib/concurrent/synchronization/mri_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +140 -73
- data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
- data/lib/concurrent/synchronization/rbx_object.rb +30 -73
- data/lib/concurrent/synchronization/volatile.rb +34 -0
- data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent/thread_safe/util.rb +14 -0
- data/lib/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +30 -0
- data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +241 -0
- data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
- data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
- data/lib/concurrent/timer_task.rb +3 -4
- data/lib/concurrent/tuple.rb +86 -0
- data/lib/concurrent/tvar.rb +5 -1
- data/lib/concurrent/utility/at_exit.rb +1 -1
- data/lib/concurrent/utility/engine.rb +4 -0
- data/lib/concurrent/utility/monotonic_time.rb +3 -4
- data/lib/concurrent/utility/native_extension_loader.rb +50 -30
- data/lib/concurrent/version.rb +2 -2
- data/lib/concurrent_ruby_ext.jar +0 -0
- metadata +47 -12
- data/lib/concurrent/atomic/condition.rb +0 -78
- data/lib/concurrent/collection/priority_queue.rb +0 -360
- data/lib/concurrent/synchronization/java_object.rb +0 -34
- data/lib/concurrent/synchronization/monitor_object.rb +0 -27
- data/lib/concurrent/synchronization/mutex_object.rb +0 -43
- data/lib/concurrent/utilities.rb +0 -5
- data/lib/concurrent/utility/timeout.rb +0 -39
- data/lib/concurrent/utility/timer.rb +0 -26
- data/lib/concurrent_ruby.rb +0 -2
@@ -7,19 +7,22 @@ module Concurrent
|
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# register = Concurrent::LazyRegister.new
|
10
|
-
# #=> #<Concurrent::LazyRegister:0x007fd7ecd5e230 @
|
10
|
+
# #=> #<Concurrent::LazyRegister:0x007fd7ecd5e230 @Data=#<Concurrent::AtomicReference:0x007fd7ecd5e1e0>>
|
11
11
|
# register[:key]
|
12
12
|
# #=> nil
|
13
13
|
# register.add(:key) { Concurrent::Actor.spawn!(Actor::AdHoc, :ping) { -> message { message } } }
|
14
|
-
# #=> #<Concurrent::LazyRegister:0x007fd7ecd5e230 @
|
14
|
+
# #=> #<Concurrent::LazyRegister:0x007fd7ecd5e230 @Data=#<Concurrent::AtomicReference:0x007fd7ecd5e1e0>>
|
15
15
|
# register[:key]
|
16
16
|
# #=> #<Concurrent::Actor::Reference /ping (Concurrent::Actor::AdHoc)>
|
17
17
|
#
|
18
18
|
# @!macro edge_warning
|
19
|
-
class LazyRegister
|
19
|
+
class LazyRegister < Synchronization::Object
|
20
|
+
|
21
|
+
private(*attr_atomic(:data))
|
20
22
|
|
21
23
|
def initialize
|
22
|
-
|
24
|
+
super
|
25
|
+
self.data = {}
|
23
26
|
end
|
24
27
|
|
25
28
|
# Element reference. Retrieves the value object corresponding to the
|
@@ -31,7 +34,7 @@ module Concurrent
|
|
31
34
|
#
|
32
35
|
# @raise Exception when the initialization block fails
|
33
36
|
def [](key)
|
34
|
-
delay =
|
37
|
+
delay = data[key]
|
35
38
|
delay ? delay.value! : nil
|
36
39
|
end
|
37
40
|
|
@@ -40,7 +43,7 @@ module Concurrent
|
|
40
43
|
# @param [Object] key
|
41
44
|
# @return [true, false] if the key is registered
|
42
45
|
def registered?(key)
|
43
|
-
|
46
|
+
data.key?(key)
|
44
47
|
end
|
45
48
|
|
46
49
|
alias_method :key?, :registered?
|
@@ -55,7 +58,7 @@ module Concurrent
|
|
55
58
|
# @return [LazyRegister] self
|
56
59
|
def register(key, &block)
|
57
60
|
delay = Delay.new(executor: :immediate, &block)
|
58
|
-
|
61
|
+
update_data { |h| h.merge(key => delay) }
|
59
62
|
self
|
60
63
|
end
|
61
64
|
|
@@ -68,7 +71,7 @@ module Concurrent
|
|
68
71
|
#
|
69
72
|
# @return [LazyRegister] self
|
70
73
|
def unregister(key)
|
71
|
-
|
74
|
+
update_data { |h| h.dup.tap { |j| j.delete(key) } }
|
72
75
|
self
|
73
76
|
end
|
74
77
|
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'concurrent/constants'
|
3
|
+
require 'concurrent/synchronization'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
# @!visibility private
|
7
|
+
module Collection
|
8
|
+
|
9
|
+
# @!visibility private
|
10
|
+
MapImplementation = if Concurrent.java_extensions_loaded?
|
11
|
+
# noinspection RubyResolve
|
12
|
+
JRubyMapBackend
|
13
|
+
elsif defined?(RUBY_ENGINE)
|
14
|
+
case RUBY_ENGINE
|
15
|
+
when 'ruby'
|
16
|
+
require 'concurrent/collection/map/mri_map_backend'
|
17
|
+
MriMapBackend
|
18
|
+
when 'rbx'
|
19
|
+
require 'concurrent/collection/map/atomic_reference_map_backend'
|
20
|
+
AtomicReferenceMapBackend
|
21
|
+
else
|
22
|
+
warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' if $VERBOSE
|
23
|
+
require 'concurrent/collection/map/synchronized_map_backend'
|
24
|
+
SynchronizedMapBackend
|
25
|
+
end
|
26
|
+
else
|
27
|
+
MriMapBackend
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# `Concurrent::Map` is a hash-like object and should have much better performance
|
32
|
+
# characteristics, especially under high concurrency, than `Concurrent::Hash`.
|
33
|
+
# However, `Concurrent::Map `is not strictly semantically equivalent to a ruby `Hash`
|
34
|
+
# -- for instance, it does not necessarily retain ordering by insertion time as `Hash`
|
35
|
+
# does. For most uses it should do fine though, and we recommend you consider
|
36
|
+
# `Concurrent::Map` instead of `Concurrent::Hash` for your concurrency-safe hash needs.
|
37
|
+
#
|
38
|
+
# > require 'concurrent'
|
39
|
+
# >
|
40
|
+
# > map = Concurrent::Map.new
|
41
|
+
|
42
|
+
class Map < Collection::MapImplementation
|
43
|
+
def initialize(options = nil, &block)
|
44
|
+
if options.kind_of?(::Hash)
|
45
|
+
validate_options_hash!(options)
|
46
|
+
else
|
47
|
+
options = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
super(options)
|
51
|
+
@default_proc = block
|
52
|
+
end
|
53
|
+
|
54
|
+
def [](key)
|
55
|
+
if value = super # non-falsy value is an existing mapping, return it right away
|
56
|
+
value
|
57
|
+
# re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call
|
58
|
+
# a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value
|
59
|
+
# would be returned)
|
60
|
+
# note: nil == value check is not technically necessary
|
61
|
+
elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL))
|
62
|
+
@default_proc.call(self, key)
|
63
|
+
else
|
64
|
+
value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
alias_method :get, :[]
|
69
|
+
alias_method :put, :[]=
|
70
|
+
|
71
|
+
def fetch(key, default_value = NULL)
|
72
|
+
if NULL != (value = get_or_default(key, NULL))
|
73
|
+
value
|
74
|
+
elsif block_given?
|
75
|
+
yield key
|
76
|
+
elsif NULL != default_value
|
77
|
+
default_value
|
78
|
+
else
|
79
|
+
raise_fetch_no_key
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def fetch_or_store(key, default_value = NULL)
|
84
|
+
fetch(key) do
|
85
|
+
put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def put_if_absent(key, value)
|
90
|
+
computed = false
|
91
|
+
result = compute_if_absent(key) do
|
92
|
+
computed = true
|
93
|
+
value
|
94
|
+
end
|
95
|
+
computed ? nil : result
|
96
|
+
end unless method_defined?(:put_if_absent)
|
97
|
+
|
98
|
+
def value?(value)
|
99
|
+
each_value do |v|
|
100
|
+
return true if value.equal?(v)
|
101
|
+
end
|
102
|
+
false
|
103
|
+
end unless method_defined?(:value?)
|
104
|
+
|
105
|
+
def keys
|
106
|
+
arr = []
|
107
|
+
each_pair {|k, v| arr << k}
|
108
|
+
arr
|
109
|
+
end unless method_defined?(:keys)
|
110
|
+
|
111
|
+
def values
|
112
|
+
arr = []
|
113
|
+
each_pair {|k, v| arr << v}
|
114
|
+
arr
|
115
|
+
end unless method_defined?(:values)
|
116
|
+
|
117
|
+
def each_key
|
118
|
+
each_pair {|k, v| yield k}
|
119
|
+
end unless method_defined?(:each_key)
|
120
|
+
|
121
|
+
def each_value
|
122
|
+
each_pair {|k, v| yield v}
|
123
|
+
end unless method_defined?(:each_value)
|
124
|
+
|
125
|
+
def key(value)
|
126
|
+
each_pair {|k, v| return k if v == value}
|
127
|
+
nil
|
128
|
+
end unless method_defined?(:key)
|
129
|
+
alias_method :index, :key if RUBY_VERSION < '1.9'
|
130
|
+
|
131
|
+
def empty?
|
132
|
+
each_pair {|k, v| return false}
|
133
|
+
true
|
134
|
+
end unless method_defined?(:empty?)
|
135
|
+
|
136
|
+
def size
|
137
|
+
count = 0
|
138
|
+
each_pair {|k, v| count += 1}
|
139
|
+
count
|
140
|
+
end unless method_defined?(:size)
|
141
|
+
|
142
|
+
def marshal_dump
|
143
|
+
raise TypeError, "can't dump hash with default proc" if @default_proc
|
144
|
+
h = {}
|
145
|
+
each_pair {|k, v| h[k] = v}
|
146
|
+
h
|
147
|
+
end
|
148
|
+
|
149
|
+
def marshal_load(hash)
|
150
|
+
initialize
|
151
|
+
populate_from(hash)
|
152
|
+
end
|
153
|
+
|
154
|
+
undef :freeze
|
155
|
+
|
156
|
+
private
|
157
|
+
def raise_fetch_no_key
|
158
|
+
raise KeyError, 'key not found'
|
159
|
+
end
|
160
|
+
|
161
|
+
def initialize_copy(other)
|
162
|
+
super
|
163
|
+
populate_from(other)
|
164
|
+
end
|
165
|
+
|
166
|
+
def populate_from(hash)
|
167
|
+
hash.each_pair {|k, v| self[k] = v}
|
168
|
+
self
|
169
|
+
end
|
170
|
+
|
171
|
+
def validate_options_hash!(options)
|
172
|
+
if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Fixnum) || initial_capacity < 0)
|
173
|
+
raise ArgumentError, ":initial_capacity must be a positive Fixnum"
|
174
|
+
end
|
175
|
+
if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1)
|
176
|
+
raise ArgumentError, ":load_factor must be a number between 0 and 1"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
data/lib/concurrent/maybe.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
2
|
+
|
1
3
|
module Concurrent
|
2
4
|
|
3
5
|
# A `Maybe` encapsulates an optional value. A `Maybe` either contains a value
|
@@ -99,8 +101,9 @@ module Concurrent
|
|
99
101
|
#
|
100
102
|
# @see https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html Haskell Data.Maybe
|
101
103
|
# @see https://github.com/purescript/purescript-maybe/blob/master/docs/Data.Maybe.md PureScript Data.Maybe
|
102
|
-
class Maybe
|
104
|
+
class Maybe < Synchronization::Object
|
103
105
|
include Comparable
|
106
|
+
safe_initialization!
|
104
107
|
|
105
108
|
# Indicates that the given attribute has not been set.
|
106
109
|
# When `Just` the {#nothing} getter will return `NONE`.
|
@@ -168,7 +171,7 @@ module Concurrent
|
|
168
171
|
end
|
169
172
|
|
170
173
|
# Is this `Maybe` a `Just` (successfully fulfilled with a value)?
|
171
|
-
#
|
174
|
+
#
|
172
175
|
# @return [Boolean] True if `Just` or false if `Nothing`.
|
173
176
|
def just?
|
174
177
|
! nothing?
|
@@ -176,7 +179,7 @@ module Concurrent
|
|
176
179
|
alias :fulfilled? :just?
|
177
180
|
|
178
181
|
# Is this `Maybe` a `nothing` (rejected with an exception upon fulfillment)?
|
179
|
-
#
|
182
|
+
#
|
180
183
|
# @return [Boolean] True if `Nothing` or false if `Just`.
|
181
184
|
def nothing?
|
182
185
|
@nothing != NONE
|
@@ -75,7 +75,7 @@ module Concurrent
|
|
75
75
|
alias_method :to_s, :inspect
|
76
76
|
|
77
77
|
# @!macro [attach] struct_merge
|
78
|
-
#
|
78
|
+
#
|
79
79
|
# Returns a new struct containing the contents of `other` and the contents
|
80
80
|
# of `self`. If no block is specified, the value for entries with duplicate
|
81
81
|
# keys will be that of `other`. Otherwise the value for each duplicate key
|
@@ -98,7 +98,7 @@ module Concurrent
|
|
98
98
|
# @!macro [attach] struct_to_h
|
99
99
|
#
|
100
100
|
# Returns a hash containing the names and values for the struct’s members.
|
101
|
-
#
|
101
|
+
#
|
102
102
|
# @return [Hash] the names and values for the struct’s members
|
103
103
|
def to_h
|
104
104
|
synchronize { ns_to_h }
|
@@ -184,8 +184,9 @@ module Concurrent
|
|
184
184
|
# @raise [IndexError] if the index is out of range.
|
185
185
|
def []=(member, value)
|
186
186
|
if member.is_a? Integer
|
187
|
-
|
188
|
-
|
187
|
+
length = synchronize { @values.length }
|
188
|
+
if member >= length
|
189
|
+
raise IndexError.new("offset #{member} too large for struct(size:#{length})")
|
189
190
|
end
|
190
191
|
synchronize { @values[member] = value }
|
191
192
|
else
|
@@ -206,10 +207,10 @@ module Concurrent
|
|
206
207
|
FACTORY.define_struct(clazz_name, args, &block)
|
207
208
|
end
|
208
209
|
|
209
|
-
FACTORY = Class.new(Synchronization::
|
210
|
+
FACTORY = Class.new(Synchronization::LockableObject) do
|
210
211
|
def define_struct(name, members, &block)
|
211
212
|
synchronize do
|
212
|
-
clazz = Synchronization::AbstractStruct.define_struct_class(MutableStruct, Synchronization::
|
213
|
+
clazz = Synchronization::AbstractStruct.define_struct_class(MutableStruct, Synchronization::LockableObject, name, members, &block)
|
213
214
|
members.each_with_index do |member, index|
|
214
215
|
clazz.send(:define_method, member) do
|
215
216
|
synchronize { @values[index] }
|
data/lib/concurrent/mvar.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'concurrent/concern/dereferenceable'
|
2
|
+
require 'concurrent/synchronization'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
|
@@ -34,9 +35,9 @@ module Concurrent
|
|
34
35
|
# 2. S. Peyton Jones, A. Gordon, and S. Finne. [Concurrent Haskell](http://dl.acm.org/citation.cfm?id=237794).
|
35
36
|
# In Proceedings of the 23rd Symposium on Principles of Programming Languages
|
36
37
|
# (PoPL), 1996.
|
37
|
-
class MVar
|
38
|
-
|
38
|
+
class MVar < Synchronization::Object
|
39
39
|
include Concern::Dereferenceable
|
40
|
+
safe_initialization!
|
40
41
|
|
41
42
|
# Unique value that represents that an `MVar` was empty
|
42
43
|
EMPTY = Object.new
|
@@ -78,6 +79,23 @@ module Concurrent
|
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
82
|
+
# acquires lock on the from an `MVAR`, yields the value to provided block,
|
83
|
+
# and release lock. A timeout can be set to limit the time spent blocked,
|
84
|
+
# in which case it returns `TIMEOUT` if the time is exceeded.
|
85
|
+
# @return [Object] the value returned by the block, or `TIMEOUT`
|
86
|
+
def borrow(timeout = nil)
|
87
|
+
@mutex.synchronize do
|
88
|
+
wait_for_full(timeout)
|
89
|
+
|
90
|
+
# if we timeoud out we'll still be empty
|
91
|
+
if unlocked_full?
|
92
|
+
yield @value
|
93
|
+
else
|
94
|
+
TIMEOUT
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
81
99
|
# Put a value into an `MVar`, blocking if there is already a value until
|
82
100
|
# it is empty. A timeout can be set to limit the time spent blocked, in
|
83
101
|
# which case it returns `TIMEOUT` if the time is exceeded.
|
@@ -183,6 +201,12 @@ module Concurrent
|
|
183
201
|
!empty?
|
184
202
|
end
|
185
203
|
|
204
|
+
protected
|
205
|
+
|
206
|
+
def synchronize(&block)
|
207
|
+
@mutex.synchronize(&block)
|
208
|
+
end
|
209
|
+
|
186
210
|
private
|
187
211
|
|
188
212
|
def unlocked_empty?
|
@@ -1,12 +1,11 @@
|
|
1
|
+
# This file has circular require issues. It must be autoloaded.
|
2
|
+
|
1
3
|
require 'concurrent/configuration'
|
2
|
-
require 'concurrent/concern/deprecation'
|
3
|
-
require 'concurrent/executor/executor_service'
|
4
4
|
|
5
5
|
module Concurrent
|
6
6
|
|
7
7
|
# @!visibility private
|
8
|
-
module
|
9
|
-
extend Concern::Deprecation
|
8
|
+
module Options
|
10
9
|
|
11
10
|
# Get the requested `Executor` based on the values set in the options hash.
|
12
11
|
#
|
@@ -20,25 +19,8 @@ module Concurrent
|
|
20
19
|
#
|
21
20
|
# @!visibility private
|
22
21
|
def self.executor_from_options(opts = {}) # :nodoc:
|
23
|
-
|
24
|
-
|
25
|
-
if opts[:executor].nil?
|
26
|
-
nil
|
27
|
-
else
|
28
|
-
executor(opts[:executor])
|
29
|
-
end
|
30
|
-
when opts.key?(:operation) || opts.key?(:task)
|
31
|
-
if opts[:operation] == true || opts[:task] == false
|
32
|
-
deprecated 'use `executor: :fast` instead'
|
33
|
-
return Concurrent.global_fast_executor
|
34
|
-
end
|
35
|
-
|
36
|
-
if opts[:operation] == false || opts[:task] == true
|
37
|
-
deprecated 'use `executor: :io` instead'
|
38
|
-
return Concurrent.global_io_executor
|
39
|
-
end
|
40
|
-
|
41
|
-
raise ArgumentError.new("executor '#{opts[:executor]}' not recognized")
|
22
|
+
if identifier = opts.fetch(:executor, nil)
|
23
|
+
executor(identifier)
|
42
24
|
else
|
43
25
|
nil
|
44
26
|
end
|
@@ -52,12 +34,6 @@ module Concurrent
|
|
52
34
|
Concurrent.global_io_executor
|
53
35
|
when :immediate
|
54
36
|
Concurrent.global_immediate_executor
|
55
|
-
when :operation
|
56
|
-
deprecated 'use `executor: :fast` instead'
|
57
|
-
Concurrent.global_fast_executor
|
58
|
-
when :task
|
59
|
-
deprecated 'use `executor: :io` instead'
|
60
|
-
Concurrent.global_io_executor
|
61
37
|
when Concurrent::ExecutorService
|
62
38
|
executor_identifier
|
63
39
|
else
|
data/lib/concurrent/promise.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'thread'
|
2
|
+
require 'concurrent/constants'
|
2
3
|
require 'concurrent/errors'
|
3
4
|
require 'concurrent/ivar'
|
4
|
-
require 'concurrent/executor/executor'
|
5
5
|
|
6
6
|
module Concurrent
|
7
7
|
|
8
|
+
autoload :Options, 'concurrent/options'
|
9
|
+
|
8
10
|
PromiseExecutionError = Class.new(StandardError)
|
9
11
|
|
10
12
|
# Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A)
|
@@ -205,7 +207,7 @@ module Concurrent
|
|
205
207
|
# @see http://promises-aplus.github.io/promises-spec/
|
206
208
|
def initialize(opts = {}, &block)
|
207
209
|
opts.delete_if { |k, v| v.nil? }
|
208
|
-
super(
|
210
|
+
super(NULL, opts.merge(__promise_body_from_block__: block), &nil)
|
209
211
|
end
|
210
212
|
|
211
213
|
# Create a new `Promise` and fulfill it immediately.
|
@@ -254,7 +256,7 @@ module Concurrent
|
|
254
256
|
# @!macro ivar_set_method
|
255
257
|
#
|
256
258
|
# @raise [Concurrent::PromiseExecutionError] if not the root promise
|
257
|
-
def set(value =
|
259
|
+
def set(value = NULL, &block)
|
258
260
|
raise PromiseExecutionError.new('supported only on root promise') unless root?
|
259
261
|
check_for_block_or_value!(block_given?, value)
|
260
262
|
synchronize do
|
@@ -302,7 +304,7 @@ module Concurrent
|
|
302
304
|
# @return [Promise] the new promise
|
303
305
|
def then(rescuer = nil, &block)
|
304
306
|
raise ArgumentError.new('rescuers and block are both missing') if rescuer.nil? && !block_given?
|
305
|
-
block = Proc.new { |result| result }
|
307
|
+
block = Proc.new { |result| result } unless block_given?
|
306
308
|
child = Promise.new(
|
307
309
|
parent: self,
|
308
310
|
executor: @executor,
|
@@ -441,7 +443,7 @@ module Concurrent
|
|
441
443
|
def ns_initialize(value, opts)
|
442
444
|
super
|
443
445
|
|
444
|
-
@executor =
|
446
|
+
@executor = Options.executor_from_options(opts) || Concurrent.global_io_executor
|
445
447
|
@args = get_arguments_from(opts)
|
446
448
|
|
447
449
|
@parent = opts.fetch(:parent) { nil }
|