concurrent-ruby 0.6.0.pre.1 → 0.6.0.pre.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +16 -0
- data/lib/concurrent.rb +9 -29
- data/lib/concurrent/{actor.rb → actor/actor.rb} +3 -3
- data/lib/concurrent/actor/actor_context.rb +77 -0
- data/lib/concurrent/actor/actor_ref.rb +67 -0
- data/lib/concurrent/{postable.rb → actor/postable.rb} +1 -1
- data/lib/concurrent/actor/simple_actor_ref.rb +94 -0
- data/lib/concurrent/actors.rb +5 -0
- data/lib/concurrent/agent.rb +81 -47
- data/lib/concurrent/async.rb +35 -35
- data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +170 -0
- data/lib/concurrent/{condition.rb → atomic/condition.rb} +0 -0
- data/lib/concurrent/{copy_on_notify_observer_set.rb → atomic/copy_on_notify_observer_set.rb} +48 -13
- data/lib/concurrent/{copy_on_write_observer_set.rb → atomic/copy_on_write_observer_set.rb} +41 -20
- data/lib/concurrent/atomic/count_down_latch.rb +116 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
- data/lib/concurrent/atomic/event.rb +103 -0
- data/lib/concurrent/{thread_local_var.rb → atomic/thread_local_var.rb} +0 -0
- data/lib/concurrent/atomics.rb +9 -0
- data/lib/concurrent/channel/buffered_channel.rb +6 -4
- data/lib/concurrent/channel/channel.rb +30 -2
- data/lib/concurrent/channel/unbuffered_channel.rb +2 -2
- data/lib/concurrent/channel/waitable_list.rb +3 -1
- data/lib/concurrent/channels.rb +5 -0
- data/lib/concurrent/{channel → collection}/blocking_ring_buffer.rb +16 -5
- data/lib/concurrent/collection/priority_queue.rb +305 -0
- data/lib/concurrent/{channel → collection}/ring_buffer.rb +6 -1
- data/lib/concurrent/collections.rb +3 -0
- data/lib/concurrent/configuration.rb +68 -19
- data/lib/concurrent/dataflow.rb +9 -9
- data/lib/concurrent/delay.rb +21 -13
- data/lib/concurrent/dereferenceable.rb +40 -33
- data/lib/concurrent/exchanger.rb +3 -0
- data/lib/concurrent/{cached_thread_pool.rb → executor/cached_thread_pool.rb} +8 -9
- data/lib/concurrent/executor/executor.rb +222 -0
- data/lib/concurrent/{fixed_thread_pool.rb → executor/fixed_thread_pool.rb} +6 -7
- data/lib/concurrent/{immediate_executor.rb → executor/immediate_executor.rb} +5 -5
- data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
- data/lib/concurrent/{java_fixed_thread_pool.rb → executor/java_fixed_thread_pool.rb} +7 -11
- data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
- data/lib/concurrent/{java_thread_pool_executor.rb → executor/java_thread_pool_executor.rb} +66 -77
- data/lib/concurrent/executor/one_by_one.rb +65 -0
- data/lib/concurrent/{per_thread_executor.rb → executor/per_thread_executor.rb} +4 -4
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
- data/lib/concurrent/{ruby_fixed_thread_pool.rb → executor/ruby_fixed_thread_pool.rb} +5 -4
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +72 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +282 -0
- data/lib/concurrent/{ruby_thread_pool_worker.rb → executor/ruby_thread_pool_worker.rb} +6 -6
- data/lib/concurrent/{safe_task_executor.rb → executor/safe_task_executor.rb} +20 -13
- data/lib/concurrent/executor/single_thread_executor.rb +35 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
- data/lib/concurrent/executor/timer_set.rb +138 -0
- data/lib/concurrent/executors.rb +9 -0
- data/lib/concurrent/future.rb +39 -40
- data/lib/concurrent/ivar.rb +22 -15
- data/lib/concurrent/mvar.rb +2 -1
- data/lib/concurrent/obligation.rb +9 -3
- data/lib/concurrent/observable.rb +33 -0
- data/lib/concurrent/options_parser.rb +46 -0
- data/lib/concurrent/promise.rb +23 -24
- data/lib/concurrent/scheduled_task.rb +21 -45
- data/lib/concurrent/timer_task.rb +204 -126
- data/lib/concurrent/tvar.rb +1 -1
- data/lib/concurrent/utilities.rb +3 -36
- data/lib/concurrent/{processor_count.rb → utility/processor_count.rb} +1 -1
- data/lib/concurrent/utility/timeout.rb +36 -0
- data/lib/concurrent/utility/timer.rb +21 -0
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.bundle +0 -0
- data/spec/concurrent/{actor_context_spec.rb → actor/actor_context_spec.rb} +0 -8
- data/spec/concurrent/{actor_ref_shared.rb → actor/actor_ref_shared.rb} +9 -59
- data/spec/concurrent/{actor_spec.rb → actor/actor_spec.rb} +43 -41
- data/spec/concurrent/{postable_shared.rb → actor/postable_shared.rb} +0 -0
- data/spec/concurrent/actor/simple_actor_ref_spec.rb +135 -0
- data/spec/concurrent/agent_spec.rb +160 -71
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +172 -0
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +186 -0
- data/spec/concurrent/{condition_spec.rb → atomic/condition_spec.rb} +2 -2
- data/spec/concurrent/{copy_on_notify_observer_set_spec.rb → atomic/copy_on_notify_observer_set_spec.rb} +0 -0
- data/spec/concurrent/{copy_on_write_observer_set_spec.rb → atomic/copy_on_write_observer_set_spec.rb} +0 -0
- data/spec/concurrent/atomic/count_down_latch_spec.rb +151 -0
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +248 -0
- data/spec/concurrent/{event_spec.rb → atomic/event_spec.rb} +18 -3
- data/spec/concurrent/{observer_set_shared.rb → atomic/observer_set_shared.rb} +15 -6
- data/spec/concurrent/{thread_local_var_spec.rb → atomic/thread_local_var_spec.rb} +0 -0
- data/spec/concurrent/channel/buffered_channel_spec.rb +1 -1
- data/spec/concurrent/channel/channel_spec.rb +6 -4
- data/spec/concurrent/channel/probe_spec.rb +37 -9
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +2 -2
- data/spec/concurrent/{channel → collection}/blocking_ring_buffer_spec.rb +0 -0
- data/spec/concurrent/collection/priority_queue_spec.rb +317 -0
- data/spec/concurrent/{channel → collection}/ring_buffer_spec.rb +0 -0
- data/spec/concurrent/configuration_spec.rb +4 -70
- data/spec/concurrent/dereferenceable_shared.rb +5 -4
- data/spec/concurrent/exchanger_spec.rb +10 -5
- data/spec/concurrent/{cached_thread_pool_shared.rb → executor/cached_thread_pool_shared.rb} +15 -37
- data/spec/concurrent/{fixed_thread_pool_shared.rb → executor/fixed_thread_pool_shared.rb} +0 -0
- data/spec/concurrent/{global_thread_pool_shared.rb → executor/global_thread_pool_shared.rb} +10 -8
- data/spec/concurrent/{immediate_executor_spec.rb → executor/immediate_executor_spec.rb} +0 -0
- data/spec/concurrent/{java_cached_thread_pool_spec.rb → executor/java_cached_thread_pool_spec.rb} +1 -21
- data/spec/concurrent/{java_fixed_thread_pool_spec.rb → executor/java_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +21 -0
- data/spec/concurrent/{java_thread_pool_executor_spec.rb → executor/java_thread_pool_executor_spec.rb} +0 -0
- data/spec/concurrent/{per_thread_executor_spec.rb → executor/per_thread_executor_spec.rb} +0 -4
- data/spec/concurrent/{ruby_cached_thread_pool_spec.rb → executor/ruby_cached_thread_pool_spec.rb} +1 -1
- data/spec/concurrent/{ruby_fixed_thread_pool_spec.rb → executor/ruby_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +18 -0
- data/spec/concurrent/{ruby_thread_pool_executor_spec.rb → executor/ruby_thread_pool_executor_spec.rb} +12 -24
- data/spec/concurrent/executor/safe_task_executor_spec.rb +103 -0
- data/spec/concurrent/{thread_pool_class_cast_spec.rb → executor/thread_pool_class_cast_spec.rb} +12 -0
- data/spec/concurrent/{thread_pool_executor_shared.rb → executor/thread_pool_executor_shared.rb} +0 -0
- data/spec/concurrent/{thread_pool_shared.rb → executor/thread_pool_shared.rb} +84 -119
- data/spec/concurrent/executor/timer_set_spec.rb +183 -0
- data/spec/concurrent/future_spec.rb +12 -0
- data/spec/concurrent/ivar_spec.rb +11 -1
- data/spec/concurrent/observable_shared.rb +173 -0
- data/spec/concurrent/observable_spec.rb +51 -0
- data/spec/concurrent/options_parser_spec.rb +71 -0
- data/spec/concurrent/runnable_shared.rb +6 -0
- data/spec/concurrent/scheduled_task_spec.rb +60 -40
- data/spec/concurrent/timer_task_spec.rb +130 -144
- data/spec/concurrent/{processor_count_spec.rb → utility/processor_count_spec.rb} +0 -0
- data/spec/concurrent/{utilities_spec.rb → utility/timeout_spec.rb} +0 -0
- data/spec/concurrent/utility/timer_spec.rb +52 -0
- metadata +147 -108
- data/lib/concurrent/actor_context.rb +0 -31
- data/lib/concurrent/actor_ref.rb +0 -39
- data/lib/concurrent/atomic.rb +0 -121
- data/lib/concurrent/channel/probe.rb +0 -19
- data/lib/concurrent/count_down_latch.rb +0 -60
- data/lib/concurrent/event.rb +0 -80
- data/lib/concurrent/java_cached_thread_pool.rb +0 -45
- data/lib/concurrent/ruby_cached_thread_pool.rb +0 -37
- data/lib/concurrent/ruby_thread_pool_executor.rb +0 -268
- data/lib/concurrent/simple_actor_ref.rb +0 -124
- data/lib/concurrent/thread_pool_executor.rb +0 -30
- data/spec/concurrent/atomic_spec.rb +0 -201
- data/spec/concurrent/count_down_latch_spec.rb +0 -125
- data/spec/concurrent/safe_task_executor_spec.rb +0 -58
- data/spec/concurrent/simple_actor_ref_spec.rb +0 -219
data/lib/concurrent/async.rb
CHANGED
@@ -2,7 +2,7 @@ require 'thread'
|
|
2
2
|
require 'concurrent/configuration'
|
3
3
|
require 'concurrent/ivar'
|
4
4
|
require 'concurrent/future'
|
5
|
-
require 'concurrent/thread_pool_executor'
|
5
|
+
require 'concurrent/executor/thread_pool_executor'
|
6
6
|
|
7
7
|
module Concurrent
|
8
8
|
|
@@ -17,20 +17,20 @@ module Concurrent
|
|
17
17
|
# Stateful, mutable objects must be managed carefully when used asynchronously.
|
18
18
|
# But Ruby is an object-oriented language so designing with objects and classes
|
19
19
|
# plays to Ruby's strengths and is often more natural to many Ruby programmers.
|
20
|
-
# The
|
20
|
+
# The `Async` module is a way to mix simple yet powerful asynchronous capabilities
|
21
21
|
# into any plain old Ruby object or class. These capabilities provide a reasonable
|
22
22
|
# level of thread safe guarantees when used correctly.
|
23
23
|
#
|
24
24
|
# When this module is mixed into a class or object it provides to new methods:
|
25
|
-
#
|
25
|
+
# `async` and `await`. These methods are thread safe with respect to the enclosing
|
26
26
|
# object. The former method allows methods to be called asynchronously by posting
|
27
27
|
# to the global thread pool. The latter allows a method to be called synchronously
|
28
28
|
# on the current thread but does so safely with respect to any pending asynchronous
|
29
|
-
# method calls. Both methods return an
|
30
|
-
# the result of the method call. Calling a method with
|
31
|
-
#
|
29
|
+
# method calls. Both methods return an `Obligation` which can be inspected for
|
30
|
+
# the result of the method call. Calling a method with `async` will return a
|
31
|
+
# `:pending` `Obligation` whereas `await` will return a `:complete` `Obligation`.
|
32
32
|
#
|
33
|
-
# Very loosely based on the
|
33
|
+
# Very loosely based on the `async` and `await` keywords in C#.
|
34
34
|
#
|
35
35
|
# @example Defining an asynchronous class
|
36
36
|
# class Echo
|
@@ -64,9 +64,9 @@ module Concurrent
|
|
64
64
|
# @note Thread safe guarantees can only be made when asynchronous method calls
|
65
65
|
# are not mixed with synchronous method calls. Use only synchronous calls
|
66
66
|
# when the object is used exclusively on a single thread. Use only
|
67
|
-
#
|
68
|
-
# call a method using
|
69
|
-
# directly on the object. Use
|
67
|
+
# `async` and `await` when the object is shared between threads. Once you
|
68
|
+
# call a method using `async`, you should no longer call any methods
|
69
|
+
# directly on the object. Use `async` and `await` exclusively from then on.
|
70
70
|
# With careful programming it is possible to switch back and forth but it's
|
71
71
|
# also very easy to create race conditions and break your application.
|
72
72
|
# Basically, it's "async all the way down."
|
@@ -83,14 +83,14 @@ module Concurrent
|
|
83
83
|
# @param [Symbol] method the method to check the object for
|
84
84
|
# @param [Array] args zero or more arguments for the arity check
|
85
85
|
#
|
86
|
-
# @raise [NameError] the object does not respond to
|
87
|
-
# @raise [ArgumentError] the given
|
86
|
+
# @raise [NameError] the object does not respond to `method` method
|
87
|
+
# @raise [ArgumentError] the given `args` do not match the arity of `method`
|
88
88
|
#
|
89
89
|
# @note This check is imperfect because of the way Ruby reports the arity of
|
90
90
|
# methods with a variable number of arguments. It is possible to determine
|
91
91
|
# if too few arguments are given but impossible to determine if too many
|
92
92
|
# arguments are given. This check may also fail to recognize dynamic behavior
|
93
|
-
# of the object, such as methods simulated with
|
93
|
+
# of the object, such as methods simulated with `method_missing`.
|
94
94
|
#
|
95
95
|
# @see http://www.ruby-doc.org/core-2.1.1/Method.html#method-i-arity Method#arity
|
96
96
|
# @see http://ruby-doc.org/core-2.1.0/Object.html#method-i-respond_to-3F Object#respond_to?
|
@@ -112,8 +112,8 @@ module Concurrent
|
|
112
112
|
# @!visibility private
|
113
113
|
class AwaitDelegator # :nodoc:
|
114
114
|
|
115
|
-
# Create a new delegator object wrapping the given
|
116
|
-
# protecting it with the given
|
115
|
+
# Create a new delegator object wrapping the given `delegate` and
|
116
|
+
# protecting it with the given `mutex`.
|
117
117
|
#
|
118
118
|
# @param [Object] delegate the object to wrap and delegate method calls to
|
119
119
|
# @param [Mutex] mutex the mutex lock to use when delegating method calls
|
@@ -124,15 +124,15 @@ module Concurrent
|
|
124
124
|
|
125
125
|
# Delegates method calls to the wrapped object. For performance,
|
126
126
|
# dynamically defines the given method on the delegator so that
|
127
|
-
# all future calls to
|
127
|
+
# all future calls to `method` will not be directed here.
|
128
128
|
#
|
129
129
|
# @param [Symbol] method the method being called
|
130
130
|
# @param [Array] args zero or more arguments to the method
|
131
131
|
#
|
132
132
|
# @return [IVar] the result of the method call
|
133
133
|
#
|
134
|
-
# @raise [NameError] the object does not respond to
|
135
|
-
# @raise [ArgumentError] the given
|
134
|
+
# @raise [NameError] the object does not respond to `method` method
|
135
|
+
# @raise [ArgumentError] the given `args` do not match the arity of `method`
|
136
136
|
def method_missing(method, *args, &block)
|
137
137
|
super unless @delegate.respond_to?(method)
|
138
138
|
Async::validate_argc(@delegate, method, *args)
|
@@ -166,8 +166,8 @@ module Concurrent
|
|
166
166
|
# @!visibility private
|
167
167
|
class AsyncDelegator # :nodoc:
|
168
168
|
|
169
|
-
# Create a new delegator object wrapping the given
|
170
|
-
# protecting it with the given
|
169
|
+
# Create a new delegator object wrapping the given `delegate` and
|
170
|
+
# protecting it with the given `mutex`.
|
171
171
|
#
|
172
172
|
# @param [Object] delegate the object to wrap and delegate method calls to
|
173
173
|
# @param [Mutex] mutex the mutex lock to use when delegating method calls
|
@@ -179,15 +179,15 @@ module Concurrent
|
|
179
179
|
|
180
180
|
# Delegates method calls to the wrapped object. For performance,
|
181
181
|
# dynamically defines the given method on the delegator so that
|
182
|
-
# all future calls to
|
182
|
+
# all future calls to `method` will not be directed here.
|
183
183
|
#
|
184
184
|
# @param [Symbol] method the method being called
|
185
185
|
# @param [Array] args zero or more arguments to the method
|
186
186
|
#
|
187
187
|
# @return [IVar] the result of the method call
|
188
188
|
#
|
189
|
-
# @raise [NameError] the object does not respond to
|
190
|
-
# @raise [ArgumentError] the given
|
189
|
+
# @raise [NameError] the object does not respond to `method` method
|
190
|
+
# @raise [ArgumentError] the given `args` do not match the arity of `method`
|
191
191
|
def method_missing(method, *args, &block)
|
192
192
|
super unless @delegate.respond_to?(method)
|
193
193
|
Async::validate_argc(@delegate, method, *args)
|
@@ -214,20 +214,20 @@ module Concurrent
|
|
214
214
|
|
215
215
|
# Causes the chained method call to be performed asynchronously on the
|
216
216
|
# global thread pool. The method called by this method will return a
|
217
|
-
#
|
217
|
+
# `Future` object in the `:pending` state and the method call will have
|
218
218
|
# been scheduled on the global thread pool. The final disposition of the
|
219
|
-
# method call can be obtained by inspecting the returned
|
219
|
+
# method call can be obtained by inspecting the returned `Future`.
|
220
220
|
#
|
221
221
|
# Before scheduling the method on the global thread pool a best-effort
|
222
222
|
# attempt will be made to validate that the method exists on the object
|
223
223
|
# and that the given arguments match the arity of the requested function.
|
224
224
|
# Due to the dynamic nature of Ruby and limitations of its reflection
|
225
225
|
# library, some edge cases will be missed. For more information see
|
226
|
-
# the documentation for the
|
226
|
+
# the documentation for the `validate_argc` method.
|
227
227
|
#
|
228
228
|
# @note The method call is guaranteed to be thread safe with respect to
|
229
229
|
# all other method calls against the same object that are called with
|
230
|
-
# either
|
230
|
+
# either `async` or `await`. The mutable nature of Ruby references
|
231
231
|
# (and object orientation in general) prevent any other thread safety
|
232
232
|
# guarantees. Do NOT mix non-protected method calls with protected
|
233
233
|
# method call. Use ONLY protected method calls when sharing the object
|
@@ -235,8 +235,8 @@ module Concurrent
|
|
235
235
|
#
|
236
236
|
# @return [Concurrent::Future] the pending result of the asynchronous operation
|
237
237
|
#
|
238
|
-
# @raise [NameError] the object does not respond to
|
239
|
-
# @raise [ArgumentError] the given
|
238
|
+
# @raise [NameError] the object does not respond to `method` method
|
239
|
+
# @raise [ArgumentError] the given `args` do not match the arity of `method`
|
240
240
|
#
|
241
241
|
# @see Concurrent::Future
|
242
242
|
def async
|
@@ -246,20 +246,20 @@ module Concurrent
|
|
246
246
|
|
247
247
|
# Causes the chained method call to be performed synchronously on the
|
248
248
|
# current thread. The method called by this method will return an
|
249
|
-
#
|
249
|
+
# `IVar` object in either the `:fulfilled` or `rejected` state and the
|
250
250
|
# method call will have completed. The final disposition of the
|
251
|
-
# method call can be obtained by inspecting the returned
|
251
|
+
# method call can be obtained by inspecting the returned `IVar`.
|
252
252
|
#
|
253
253
|
# Before scheduling the method on the global thread pool a best-effort
|
254
254
|
# attempt will be made to validate that the method exists on the object
|
255
255
|
# and that the given arguments match the arity of the requested function.
|
256
256
|
# Due to the dynamic nature of Ruby and limitations of its reflection
|
257
257
|
# library, some edge cases will be missed. For more information see
|
258
|
-
# the documentation for the
|
258
|
+
# the documentation for the `validate_argc` method.
|
259
259
|
#
|
260
260
|
# @note The method call is guaranteed to be thread safe with respect to
|
261
261
|
# all other method calls against the same object that are called with
|
262
|
-
# either
|
262
|
+
# either `async` or `await`. The mutable nature of Ruby references
|
263
263
|
# (and object orientation in general) prevent any other thread safety
|
264
264
|
# guarantees. Do NOT mix non-protected method calls with protected
|
265
265
|
# method call. Use ONLY protected method calls when sharing the object
|
@@ -267,8 +267,8 @@ module Concurrent
|
|
267
267
|
#
|
268
268
|
# @return [Concurrent::IVar] the completed result of the synchronous operation
|
269
269
|
#
|
270
|
-
# @raise [NameError] the object does not respond to
|
271
|
-
# @raise [ArgumentError] the given
|
270
|
+
# @raise [NameError] the object does not respond to `method` method
|
271
|
+
# @raise [ArgumentError] the given `args` do not match the arity of `method`
|
272
272
|
#
|
273
273
|
# @see Concurrent::IVar
|
274
274
|
def await
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module Concurrent
|
2
|
+
|
3
|
+
# @!macro [attach] atomic_boolean
|
4
|
+
#
|
5
|
+
# A boolean value that can be updated atomically. Reads and writes to an atomic
|
6
|
+
# boolean and thread-safe and guaranteed to succeed. Reads and writes may block
|
7
|
+
# briefly but no explicit locking is required.
|
8
|
+
#
|
9
|
+
# @since 0.6.0
|
10
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean
|
11
|
+
class MutexAtomicBoolean
|
12
|
+
|
13
|
+
# @!macro [attach] atomic_boolean_method_initialize
|
14
|
+
#
|
15
|
+
# Creates a new `AtomicBoolean` with the given initial value.
|
16
|
+
#
|
17
|
+
# @param [Boolean] init the initial value
|
18
|
+
def initialize(initial = false)
|
19
|
+
@value = !!initial
|
20
|
+
@mutex = Mutex.new
|
21
|
+
end
|
22
|
+
|
23
|
+
# @!macro [attach] atomic_boolean_method_value
|
24
|
+
#
|
25
|
+
# Retrieves the current `Boolean` value.
|
26
|
+
#
|
27
|
+
# @return [Boolean] the current value
|
28
|
+
def value
|
29
|
+
@mutex.lock
|
30
|
+
result = @value
|
31
|
+
@mutex.unlock
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
# @!macro [attach] atomic_boolean_method_value_eq
|
36
|
+
#
|
37
|
+
# Explicitly sets the value.
|
38
|
+
#
|
39
|
+
# @param [Boolean] value the new value to be set
|
40
|
+
#
|
41
|
+
# @return [Boolean] the current value
|
42
|
+
def value=(value)
|
43
|
+
@mutex.lock
|
44
|
+
@value = !!value
|
45
|
+
result = @value
|
46
|
+
@mutex.unlock
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
# @!macro [attach] atomic_boolean_method_is_true
|
51
|
+
#
|
52
|
+
# Is the current value `true`?
|
53
|
+
#
|
54
|
+
# @return [Boolean] true if the current value is `true`, else false
|
55
|
+
def true?
|
56
|
+
@mutex.lock
|
57
|
+
result = @value
|
58
|
+
@mutex.unlock
|
59
|
+
result
|
60
|
+
end
|
61
|
+
|
62
|
+
# @!macro [attach] atomic_boolean_method_is_false
|
63
|
+
#
|
64
|
+
# Is the current value `true`?false
|
65
|
+
#
|
66
|
+
# @return [Boolean] true if the current value is `false`, else false
|
67
|
+
def false?
|
68
|
+
@mutex.lock
|
69
|
+
result = !@value
|
70
|
+
@mutex.unlock
|
71
|
+
result
|
72
|
+
end
|
73
|
+
|
74
|
+
# @!macro [attach] atomic_boolean_method_make_true
|
75
|
+
#
|
76
|
+
# Explicitly sets the value to true.
|
77
|
+
#
|
78
|
+
# @return [Boolean] true is value has changed, otherwise false
|
79
|
+
def make_true
|
80
|
+
@mutex.lock
|
81
|
+
old = @value
|
82
|
+
@value = true
|
83
|
+
@mutex.unlock
|
84
|
+
|
85
|
+
!old
|
86
|
+
end
|
87
|
+
|
88
|
+
# @!macro [attach] atomic_boolean_method_make_false
|
89
|
+
#
|
90
|
+
# Explicitly sets the value to false.
|
91
|
+
#
|
92
|
+
# @return [Boolean] true is value has changed, otherwise false
|
93
|
+
def make_false
|
94
|
+
@mutex.lock
|
95
|
+
old = @value
|
96
|
+
@value = false
|
97
|
+
@mutex.unlock
|
98
|
+
|
99
|
+
old
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
if RUBY_PLATFORM == 'java'
|
104
|
+
|
105
|
+
# @!macro atomic_boolean
|
106
|
+
class JavaAtomicBoolean
|
107
|
+
|
108
|
+
# @!macro atomic_boolean_method_initialize
|
109
|
+
#
|
110
|
+
def initialize(initial = false)
|
111
|
+
@atomic = java.util.concurrent.atomic.AtomicBoolean.new(!!initial)
|
112
|
+
end
|
113
|
+
|
114
|
+
# @!macro atomic_boolean_method_value
|
115
|
+
#
|
116
|
+
def value
|
117
|
+
@atomic.get
|
118
|
+
end
|
119
|
+
|
120
|
+
# @!macro atomic_boolean_method_value_eq
|
121
|
+
#
|
122
|
+
def value=(value)
|
123
|
+
@atomic.set(!!value)
|
124
|
+
end
|
125
|
+
|
126
|
+
# @!macro [attach] atomic_boolean_method_is_true
|
127
|
+
def true?
|
128
|
+
@atomic.get
|
129
|
+
end
|
130
|
+
|
131
|
+
# @!macro [attach] atomic_boolean_method_is_false
|
132
|
+
def false?
|
133
|
+
!@atomic.get
|
134
|
+
end
|
135
|
+
|
136
|
+
# @!macro atomic_boolean_method_make_true
|
137
|
+
def make_true
|
138
|
+
@atomic.compareAndSet(false, true)
|
139
|
+
end
|
140
|
+
|
141
|
+
# @!macro atomic_boolean_method_make_false
|
142
|
+
def make_false
|
143
|
+
@atomic.compareAndSet(true, false)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# @!macro atomic_boolean
|
148
|
+
class AtomicBoolean < JavaAtomicBoolean
|
149
|
+
end
|
150
|
+
|
151
|
+
else
|
152
|
+
|
153
|
+
# @!macro atomic_boolean
|
154
|
+
class AtomicBoolean < MutexAtomicBoolean
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
module Concurrent
|
2
|
+
|
3
|
+
# @!macro [attach] atomic_fixnum
|
4
|
+
#
|
5
|
+
# A numeric value that can be updated atomically. Reads and writes to an atomic
|
6
|
+
# fixnum and thread-safe and guaranteed to succeed. Reads and writes may block
|
7
|
+
# briefly but no explicit locking is required.
|
8
|
+
#
|
9
|
+
# @since 0.5.0
|
10
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong
|
11
|
+
class MutexAtomicFixnum
|
12
|
+
|
13
|
+
# @!macro [attach] atomic_fixnum_method_initialize
|
14
|
+
#
|
15
|
+
# Creates a new `AtomicFixnum` with the given initial value.
|
16
|
+
#
|
17
|
+
# @param [Fixnum] init the initial value
|
18
|
+
# @raise [ArgumentError] if the initial value is not a `Fixnum`
|
19
|
+
def initialize(init = 0)
|
20
|
+
raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum)
|
21
|
+
@value = init
|
22
|
+
@mutex = Mutex.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!macro [attach] atomic_fixnum_method_value
|
26
|
+
#
|
27
|
+
# Retrieves the current `Fixnum` value.
|
28
|
+
#
|
29
|
+
# @return [Fixnum] the current value
|
30
|
+
def value
|
31
|
+
@mutex.lock
|
32
|
+
result = @value
|
33
|
+
@mutex.unlock
|
34
|
+
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
# @!macro [attach] atomic_fixnum_method_value_eq
|
39
|
+
#
|
40
|
+
# Explicitly sets the value.
|
41
|
+
#
|
42
|
+
# @param [Fixnum] value the new value to be set
|
43
|
+
#
|
44
|
+
# @return [Fixnum] the current value
|
45
|
+
#
|
46
|
+
# @raise [ArgumentError] if the new value is not a `Fixnum`
|
47
|
+
def value=(value)
|
48
|
+
raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
|
49
|
+
@mutex.lock
|
50
|
+
result = @value = value
|
51
|
+
@mutex.unlock
|
52
|
+
|
53
|
+
result
|
54
|
+
end
|
55
|
+
|
56
|
+
# @!macro [attach] atomic_fixnum_method_increment
|
57
|
+
#
|
58
|
+
# Increases the current value by 1.
|
59
|
+
#
|
60
|
+
# @return [Fixnum] the current value after incrementation
|
61
|
+
def increment
|
62
|
+
@mutex.lock
|
63
|
+
@value += 1
|
64
|
+
result = @value
|
65
|
+
@mutex.unlock
|
66
|
+
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
alias_method :up, :increment
|
71
|
+
|
72
|
+
# @!macro [attach] atomic_fixnum_method_decrement
|
73
|
+
#
|
74
|
+
# Decreases the current value by 1.
|
75
|
+
#
|
76
|
+
# @return [Fixnum] the current value after decrementation
|
77
|
+
def decrement
|
78
|
+
@mutex.lock
|
79
|
+
@value -= 1
|
80
|
+
result = @value
|
81
|
+
@mutex.unlock
|
82
|
+
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
alias_method :down, :decrement
|
87
|
+
|
88
|
+
# @!macro [attach] atomic_fixnum_method_compare_and_set
|
89
|
+
#
|
90
|
+
# Atomically sets the value to the given updated value if the current
|
91
|
+
# value == the expected value.
|
92
|
+
#
|
93
|
+
# @param [Fixnum] expect the expected value
|
94
|
+
# @param [Fixnum] update the new value
|
95
|
+
#
|
96
|
+
# @return [Boolean] true if the value was updated else false
|
97
|
+
def compare_and_set(expect, update)
|
98
|
+
|
99
|
+
@mutex.lock
|
100
|
+
if @value == expect
|
101
|
+
@value = update
|
102
|
+
result = true
|
103
|
+
else
|
104
|
+
result = false
|
105
|
+
end
|
106
|
+
@mutex.unlock
|
107
|
+
|
108
|
+
result
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
if RUBY_PLATFORM == 'java'
|
113
|
+
|
114
|
+
# @!macro atomic_fixnum
|
115
|
+
class JavaAtomicFixnum
|
116
|
+
|
117
|
+
# @!macro atomic_fixnum_method_initialize
|
118
|
+
#
|
119
|
+
def initialize(init = 0)
|
120
|
+
raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum)
|
121
|
+
@atomic = java.util.concurrent.atomic.AtomicLong.new(init)
|
122
|
+
end
|
123
|
+
|
124
|
+
# @!macro atomic_fixnum_method_value
|
125
|
+
#
|
126
|
+
def value
|
127
|
+
@atomic.get
|
128
|
+
end
|
129
|
+
|
130
|
+
# @!macro atomic_fixnum_method_value_eq
|
131
|
+
#
|
132
|
+
def value=(value)
|
133
|
+
raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
|
134
|
+
@atomic.set(value)
|
135
|
+
end
|
136
|
+
|
137
|
+
# @!macro atomic_fixnum_method_increment
|
138
|
+
#
|
139
|
+
def increment
|
140
|
+
@atomic.increment_and_get
|
141
|
+
end
|
142
|
+
|
143
|
+
alias_method :up, :increment
|
144
|
+
|
145
|
+
# @!macro atomic_fixnum_method_decrement
|
146
|
+
#
|
147
|
+
def decrement
|
148
|
+
@atomic.decrement_and_get
|
149
|
+
end
|
150
|
+
|
151
|
+
alias_method :down, :decrement
|
152
|
+
|
153
|
+
# @!macro atomic_fixnum_method_compare_and_set
|
154
|
+
#
|
155
|
+
def compare_and_set(expect, update)
|
156
|
+
@atomic.compare_and_set(expect, update)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# @!macro atomic_fixnum
|
161
|
+
class AtomicFixnum < JavaAtomicFixnum
|
162
|
+
end
|
163
|
+
|
164
|
+
else
|
165
|
+
|
166
|
+
# @!macro atomic_fixnum
|
167
|
+
class AtomicFixnum < MutexAtomicFixnum
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|