concurrent-ruby 1.0.5 → 1.1.10
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 +5 -5
- data/CHANGELOG.md +155 -0
- data/Gemfile +37 -0
- data/LICENSE.txt +18 -18
- data/README.md +260 -103
- data/Rakefile +329 -0
- data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +189 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +7 -7
- data/lib/concurrent-ruby/concurrent/array.rb +66 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +28 -24
- data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +10 -10
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +26 -22
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +27 -23
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +7 -7
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +3 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +9 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +18 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +7 -7
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +60 -40
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +34 -13
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +8 -8
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +3 -8
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +3 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +1 -2
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +30 -30
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +3 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +6 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +7 -7
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +15 -15
- data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +9 -7
- data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +21 -25
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +35 -38
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +5 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +17 -17
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +47 -33
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +20 -17
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +29 -9
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +5 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +3 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +7 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +14 -17
- data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +4 -1
- data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +9 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +5 -6
- data/lib/concurrent-ruby/concurrent/map.rb +346 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +27 -16
- data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +54 -21
- data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
- data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +29 -16
- data/lib/concurrent-ruby/concurrent/set.rb +74 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +12 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +18 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +8 -10
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +53 -23
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +6 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +11 -9
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +4 -5
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +9 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +15 -35
- data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +21 -58
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +4 -4
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -35
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
- data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +24 -20
- metadata +149 -134
- data/lib/concurrent/array.rb +0 -39
- data/lib/concurrent/atomic/atomic_reference.rb +0 -51
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
- data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
- data/lib/concurrent/atomic_reference/jruby.rb +0 -16
- data/lib/concurrent/atomic_reference/rbx.rb +0 -22
- data/lib/concurrent/atomic_reference/ruby.rb +0 -32
- data/lib/concurrent/atomics.rb +0 -53
- data/lib/concurrent/edge.rb +0 -26
- data/lib/concurrent/hash.rb +0 -36
- data/lib/concurrent/lazy_register.rb +0 -81
- data/lib/concurrent/map.rb +0 -240
- data/lib/concurrent/synchronization/mri_lockable_object.rb +0 -71
- data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
- data/lib/concurrent/synchronization/truffle_object.rb +0 -31
- data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
- data/lib/concurrent/utility/at_exit.rb +0 -97
- data/lib/concurrent/utility/monotonic_time.rb +0 -58
- data/lib/concurrent/utility/native_extension_loader.rb +0 -73
- data/lib/concurrent/version.rb +0 -4
- /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
@@ -129,7 +129,7 @@ module Concurrent
|
|
129
129
|
# end
|
130
130
|
# ```
|
131
131
|
#
|
132
|
-
# @!macro
|
132
|
+
# @!macro agent_await_warning
|
133
133
|
#
|
134
134
|
# **NOTE** Never, *under any circumstances*, call any of the "await" methods
|
135
135
|
# ({#await}, {#await_for}, {#await_for!}, and {#wait}) from within an action
|
@@ -147,7 +147,7 @@ module Concurrent
|
|
147
147
|
ERROR_MODES = [:continue, :fail].freeze
|
148
148
|
private_constant :ERROR_MODES
|
149
149
|
|
150
|
-
AWAIT_FLAG = Object.new
|
150
|
+
AWAIT_FLAG = ::Object.new
|
151
151
|
private_constant :AWAIT_FLAG
|
152
152
|
|
153
153
|
AWAIT_ACTION = ->(value, latch) { latch.count_down; AWAIT_FLAG }
|
@@ -242,7 +242,7 @@ module Concurrent
|
|
242
242
|
|
243
243
|
alias_method :reason, :error
|
244
244
|
|
245
|
-
# @!macro
|
245
|
+
# @!macro agent_send
|
246
246
|
#
|
247
247
|
# Dispatches an action to the Agent and returns immediately. Subsequently,
|
248
248
|
# in a thread from a thread pool, the {#value} will be set to the return
|
@@ -271,7 +271,7 @@ module Concurrent
|
|
271
271
|
# action
|
272
272
|
# @yieldreturn [Object] the new value of the Agent
|
273
273
|
#
|
274
|
-
# @!macro
|
274
|
+
# @!macro send_return
|
275
275
|
# @return [Boolean] true if the action is successfully enqueued, false if
|
276
276
|
# the Agent is {#failed?}
|
277
277
|
def send(*args, &action)
|
@@ -280,7 +280,7 @@ module Concurrent
|
|
280
280
|
|
281
281
|
# @!macro agent_send
|
282
282
|
#
|
283
|
-
# @!macro
|
283
|
+
# @!macro send_bang_return_and_raise
|
284
284
|
# @return [Boolean] true if the action is successfully enqueued
|
285
285
|
# @raise [Concurrent::Agent::Error] if the Agent is {#failed?}
|
286
286
|
def send!(*args, &action)
|
@@ -326,7 +326,7 @@ module Concurrent
|
|
326
326
|
#
|
327
327
|
# @param [Proc] action the action dispatch to be enqueued
|
328
328
|
# @return [Concurrent::Agent] self
|
329
|
-
# @see
|
329
|
+
# @see #send_off
|
330
330
|
def <<(action)
|
331
331
|
send_off(&action)
|
332
332
|
self
|
@@ -397,7 +397,7 @@ module Concurrent
|
|
397
397
|
|
398
398
|
# Is the Agent in a failed state?
|
399
399
|
#
|
400
|
-
# @see
|
400
|
+
# @see #restart
|
401
401
|
def failed?
|
402
402
|
!@error.value.nil?
|
403
403
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/thread_safe/util'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!macro concurrent_array
|
7
|
+
#
|
8
|
+
# A thread-safe subclass of Array. This version locks against the object
|
9
|
+
# itself for every method call, ensuring only one thread can be reading
|
10
|
+
# or writing at a time. This includes iteration methods like `#each`.
|
11
|
+
#
|
12
|
+
# @note `a += b` is **not** a **thread-safe** operation on
|
13
|
+
# `Concurrent::Array`. It reads array `a`, then it creates new `Concurrent::Array`
|
14
|
+
# which is concatenation of `a` and `b`, then it writes the concatenation to `a`.
|
15
|
+
# The read and write are independent operations they do not form a single atomic
|
16
|
+
# operation therefore when two `+=` operations are executed concurrently updates
|
17
|
+
# may be lost. Use `#concat` instead.
|
18
|
+
#
|
19
|
+
# @see http://ruby-doc.org/core/Array.html Ruby standard library `Array`
|
20
|
+
|
21
|
+
# @!macro internal_implementation_note
|
22
|
+
ArrayImplementation = case
|
23
|
+
when Concurrent.on_cruby?
|
24
|
+
# Array is thread-safe in practice because CRuby runs
|
25
|
+
# threads one at a time and does not do context
|
26
|
+
# switching during the execution of C functions.
|
27
|
+
::Array
|
28
|
+
|
29
|
+
when Concurrent.on_jruby?
|
30
|
+
require 'jruby/synchronized'
|
31
|
+
|
32
|
+
class JRubyArray < ::Array
|
33
|
+
include JRuby::Synchronized
|
34
|
+
end
|
35
|
+
JRubyArray
|
36
|
+
|
37
|
+
when Concurrent.on_rbx?
|
38
|
+
require 'monitor'
|
39
|
+
require 'concurrent/thread_safe/util/data_structures'
|
40
|
+
|
41
|
+
class RbxArray < ::Array
|
42
|
+
end
|
43
|
+
|
44
|
+
ThreadSafe::Util.make_synchronized_on_rbx RbxArray
|
45
|
+
RbxArray
|
46
|
+
|
47
|
+
when Concurrent.on_truffleruby?
|
48
|
+
require 'concurrent/thread_safe/util/data_structures'
|
49
|
+
|
50
|
+
class TruffleRubyArray < ::Array
|
51
|
+
end
|
52
|
+
|
53
|
+
ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubyArray
|
54
|
+
TruffleRubyArray
|
55
|
+
|
56
|
+
else
|
57
|
+
warn 'Possibly unsupported Ruby implementation'
|
58
|
+
::Array
|
59
|
+
end
|
60
|
+
private_constant :ArrayImplementation
|
61
|
+
|
62
|
+
# @!macro concurrent_array
|
63
|
+
class Array < ArrayImplementation
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -58,26 +58,6 @@ module Concurrent
|
|
58
58
|
# end
|
59
59
|
# ```
|
60
60
|
#
|
61
|
-
# When defining a constructor it is critical that the first line be a call to
|
62
|
-
# `super` with no arguments. The `super` method initializes the background
|
63
|
-
# thread and other asynchronous components.
|
64
|
-
#
|
65
|
-
# ```
|
66
|
-
# class BackgroundLogger
|
67
|
-
# include Concurrent::Async
|
68
|
-
#
|
69
|
-
# def initialize(level)
|
70
|
-
# super()
|
71
|
-
# @logger = Logger.new(STDOUT)
|
72
|
-
# @logger.level = level
|
73
|
-
# end
|
74
|
-
#
|
75
|
-
# def info(msg)
|
76
|
-
# @logger.info(msg)
|
77
|
-
# end
|
78
|
-
# end
|
79
|
-
# ```
|
80
|
-
#
|
81
61
|
# Mixing this module into a class provides each object two proxy methods:
|
82
62
|
# `async` and `await`. These methods are thread safe with respect to the
|
83
63
|
# enclosing object. The former proxy allows methods to be called
|
@@ -159,7 +139,7 @@ module Concurrent
|
|
159
139
|
#
|
160
140
|
# To get the state *at the current* time, irrespective of an enqueued method
|
161
141
|
# calls, a reader method must be called directly. This is inherently unsafe
|
162
|
-
# unless the instance variable is itself thread-safe,
|
142
|
+
# unless the instance variable is itself thread-safe, preferably using one
|
163
143
|
# of the thread-safe classes within this library. Because the thread-safe
|
164
144
|
# classes within this library are internally-locking or non-locking, they can
|
165
145
|
# be safely used from within asynchronous methods without causing deadlocks.
|
@@ -188,7 +168,7 @@ module Concurrent
|
|
188
168
|
#
|
189
169
|
# Class variables should be avoided. Class variables represent shared state.
|
190
170
|
# Shared state is anathema to concurrency. Should there be a need to share
|
191
|
-
# state using class variables they *must* be thread-safe,
|
171
|
+
# state using class variables they *must* be thread-safe, preferably
|
192
172
|
# using the thread-safe classes within this library. When updating class
|
193
173
|
# variables, never assign a new value/object to the variable itself. Assignment
|
194
174
|
# is not thread-safe in Ruby. Instead, use the thread-safe update functions
|
@@ -292,6 +272,7 @@ module Concurrent
|
|
292
272
|
obj.send(:init_synchronization)
|
293
273
|
obj
|
294
274
|
end
|
275
|
+
ruby2_keywords :new if respond_to?(:ruby2_keywords, true)
|
295
276
|
end
|
296
277
|
private_constant :ClassMethods
|
297
278
|
|
@@ -309,6 +290,7 @@ module Concurrent
|
|
309
290
|
@delegate = delegate
|
310
291
|
@queue = []
|
311
292
|
@executor = Concurrent.global_io_executor
|
293
|
+
@ruby_pid = $$
|
312
294
|
end
|
313
295
|
|
314
296
|
# Delegates method calls to the wrapped object.
|
@@ -326,6 +308,7 @@ module Concurrent
|
|
326
308
|
|
327
309
|
ivar = Concurrent::IVar.new
|
328
310
|
synchronize do
|
311
|
+
reset_if_forked
|
329
312
|
@queue.push [ivar, method, args, block]
|
330
313
|
@executor.post { perform } if @queue.length == 1
|
331
314
|
end
|
@@ -333,6 +316,13 @@ module Concurrent
|
|
333
316
|
ivar
|
334
317
|
end
|
335
318
|
|
319
|
+
# Check whether the method is responsive
|
320
|
+
#
|
321
|
+
# @param [Symbol] method the method being called
|
322
|
+
def respond_to_missing?(method, include_private = false)
|
323
|
+
@delegate.respond_to?(method) || super
|
324
|
+
end
|
325
|
+
|
336
326
|
# Perform all enqueued tasks.
|
337
327
|
#
|
338
328
|
# This method must be called from within the executor. It must not be
|
@@ -354,6 +344,13 @@ module Concurrent
|
|
354
344
|
end
|
355
345
|
end
|
356
346
|
end
|
347
|
+
|
348
|
+
def reset_if_forked
|
349
|
+
if $$ != @ruby_pid
|
350
|
+
@queue.clear
|
351
|
+
@ruby_pid = $$
|
352
|
+
end
|
353
|
+
end
|
357
354
|
end
|
358
355
|
private_constant :AsyncDelegator
|
359
356
|
|
@@ -383,6 +380,13 @@ module Concurrent
|
|
383
380
|
ivar.wait
|
384
381
|
ivar
|
385
382
|
end
|
383
|
+
|
384
|
+
# Check whether the method is responsive
|
385
|
+
#
|
386
|
+
# @param [Symbol] method the method being called
|
387
|
+
def respond_to_missing?(method, include_private = false)
|
388
|
+
@delegate.respond_to?(method) || super
|
389
|
+
end
|
386
390
|
end
|
387
391
|
private_constant :AwaitDelegator
|
388
392
|
|
@@ -392,7 +396,7 @@ module Concurrent
|
|
392
396
|
# object's thread. The final disposition of the method call can be obtained
|
393
397
|
# by inspecting the returned future.
|
394
398
|
#
|
395
|
-
# @!macro
|
399
|
+
# @!macro async_thread_safety_warning
|
396
400
|
# @note The method call is guaranteed to be thread safe with respect to
|
397
401
|
# all other method calls against the same object that are called with
|
398
402
|
# either `async` or `await`. The mutable nature of Ruby references
|
@@ -435,7 +439,7 @@ module Concurrent
|
|
435
439
|
#
|
436
440
|
# @!visibility private
|
437
441
|
def init_synchronization
|
438
|
-
return self if @__async_initialized__
|
442
|
+
return self if defined?(@__async_initialized__) && @__async_initialized__
|
439
443
|
@__async_initialized__ = true
|
440
444
|
@__async_delegator__ = AsyncDelegator.new(self)
|
441
445
|
@__await_delegator__ = AwaitDelegator.new(@__async_delegator__)
|
@@ -3,7 +3,7 @@ require 'concurrent/collection/copy_on_notify_observer_set'
|
|
3
3
|
require 'concurrent/concern/observable'
|
4
4
|
require 'concurrent/synchronization'
|
5
5
|
|
6
|
-
# @!macro
|
6
|
+
# @!macro thread_safe_variable_comparison
|
7
7
|
#
|
8
8
|
# ## Thread-safe Variable Classes
|
9
9
|
#
|
@@ -18,7 +18,7 @@ require 'concurrent/synchronization'
|
|
18
18
|
# uncoordinated, *synchronous* change of individual values. Best used when
|
19
19
|
# the value will undergo frequent reads but only occasional, though complex,
|
20
20
|
# updates. Suitable when the result of an update must be known immediately.
|
21
|
-
# * *{Concurrent::AtomicReference}:* A simple object reference that can be
|
21
|
+
# * *{Concurrent::AtomicReference}:* A simple object reference that can be updated
|
22
22
|
# atomically. Updates are synchronous but fast. Best used when updates a
|
23
23
|
# simple set operations. Not suitable when updates are complex.
|
24
24
|
# {Concurrent::AtomicBoolean} and {Concurrent::AtomicFixnum} are similar
|
@@ -96,8 +96,15 @@ module Concurrent
|
|
96
96
|
include Concern::Observable
|
97
97
|
|
98
98
|
safe_initialization!
|
99
|
-
|
99
|
+
attr_atomic(:value)
|
100
|
+
private :value=, :swap_value, :compare_and_set_value, :update_value
|
100
101
|
public :value
|
102
|
+
alias_method :deref, :value
|
103
|
+
|
104
|
+
# @!method value
|
105
|
+
# The current value of the atom.
|
106
|
+
#
|
107
|
+
# @return [Object] The current value.
|
101
108
|
|
102
109
|
# Create a new atom with the given initial value.
|
103
110
|
#
|
@@ -118,13 +125,6 @@ module Concurrent
|
|
118
125
|
self.value = value
|
119
126
|
end
|
120
127
|
|
121
|
-
# @!method value
|
122
|
-
# The current value of the atom.
|
123
|
-
#
|
124
|
-
# @return [Object] The current value.
|
125
|
-
|
126
|
-
alias_method :deref, :value
|
127
|
-
|
128
128
|
# Atomically swaps the value of atom using the given block. The current
|
129
129
|
# value will be passed to the block, as will any arguments passed as
|
130
130
|
# arguments to the function. The new value will be validated against the
|
@@ -5,19 +5,19 @@ module Concurrent
|
|
5
5
|
|
6
6
|
###################################################################
|
7
7
|
|
8
|
-
# @!macro
|
8
|
+
# @!macro atomic_boolean_method_initialize
|
9
9
|
#
|
10
10
|
# Creates a new `AtomicBoolean` with the given initial value.
|
11
11
|
#
|
12
12
|
# @param [Boolean] initial the initial value
|
13
13
|
|
14
|
-
# @!macro
|
14
|
+
# @!macro atomic_boolean_method_value_get
|
15
15
|
#
|
16
16
|
# Retrieves the current `Boolean` value.
|
17
17
|
#
|
18
18
|
# @return [Boolean] the current value
|
19
19
|
|
20
|
-
# @!macro
|
20
|
+
# @!macro atomic_boolean_method_value_set
|
21
21
|
#
|
22
22
|
# Explicitly sets the value.
|
23
23
|
#
|
@@ -25,33 +25,33 @@ module Concurrent
|
|
25
25
|
#
|
26
26
|
# @return [Boolean] the current value
|
27
27
|
|
28
|
-
# @!macro
|
28
|
+
# @!macro atomic_boolean_method_true_question
|
29
29
|
#
|
30
30
|
# Is the current value `true`
|
31
31
|
#
|
32
32
|
# @return [Boolean] true if the current value is `true`, else false
|
33
33
|
|
34
|
-
# @!macro
|
34
|
+
# @!macro atomic_boolean_method_false_question
|
35
35
|
#
|
36
36
|
# Is the current value `false`
|
37
37
|
#
|
38
38
|
# @return [Boolean] true if the current value is `false`, else false
|
39
39
|
|
40
|
-
# @!macro
|
40
|
+
# @!macro atomic_boolean_method_make_true
|
41
41
|
#
|
42
42
|
# Explicitly sets the value to true.
|
43
43
|
#
|
44
|
-
# @return [Boolean] true
|
44
|
+
# @return [Boolean] true if value has changed, otherwise false
|
45
45
|
|
46
|
-
# @!macro
|
46
|
+
# @!macro atomic_boolean_method_make_false
|
47
47
|
#
|
48
48
|
# Explicitly sets the value to false.
|
49
49
|
#
|
50
|
-
# @return [Boolean] true
|
50
|
+
# @return [Boolean] true if value has changed, otherwise false
|
51
51
|
|
52
52
|
###################################################################
|
53
53
|
|
54
|
-
# @!macro
|
54
|
+
# @!macro atomic_boolean_public_api
|
55
55
|
#
|
56
56
|
# @!method initialize(initial = false)
|
57
57
|
# @!macro atomic_boolean_method_initialize
|
@@ -88,7 +88,7 @@ module Concurrent
|
|
88
88
|
end
|
89
89
|
private_constant :AtomicBooleanImplementation
|
90
90
|
|
91
|
-
# @!macro
|
91
|
+
# @!macro atomic_boolean
|
92
92
|
#
|
93
93
|
# A boolean value that can be updated atomically. Reads and writes to an atomic
|
94
94
|
# boolean and thread-safe and guaranteed to succeed. Reads and writes may block
|
@@ -96,17 +96,21 @@ module Concurrent
|
|
96
96
|
#
|
97
97
|
# @!macro thread_safe_variable_comparison
|
98
98
|
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
99
|
+
# Performance:
|
100
|
+
#
|
101
|
+
# ```
|
102
|
+
# Testing with ruby 2.1.2
|
103
|
+
# Testing with Concurrent::MutexAtomicBoolean...
|
104
|
+
# 2.790000 0.000000 2.790000 ( 2.791454)
|
105
|
+
# Testing with Concurrent::CAtomicBoolean...
|
106
|
+
# 0.740000 0.000000 0.740000 ( 0.740206)
|
104
107
|
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
108
|
+
# Testing with jruby 1.9.3
|
109
|
+
# Testing with Concurrent::MutexAtomicBoolean...
|
110
|
+
# 5.240000 2.520000 7.760000 ( 3.683000)
|
111
|
+
# Testing with Concurrent::JavaAtomicBoolean...
|
112
|
+
# 3.340000 0.010000 3.350000 ( 0.855000)
|
113
|
+
# ```
|
110
114
|
#
|
111
115
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean
|
112
116
|
#
|
@@ -114,7 +118,7 @@ module Concurrent
|
|
114
118
|
class AtomicBoolean < AtomicBooleanImplementation
|
115
119
|
# @return [String] Short string representation.
|
116
120
|
def to_s
|
117
|
-
format '
|
121
|
+
format '%s value:%s>', super[0..-2], value
|
118
122
|
end
|
119
123
|
|
120
124
|
alias_method :inspect, :to_s
|
@@ -5,20 +5,20 @@ module Concurrent
|
|
5
5
|
|
6
6
|
###################################################################
|
7
7
|
|
8
|
-
# @!macro
|
8
|
+
# @!macro atomic_fixnum_method_initialize
|
9
9
|
#
|
10
10
|
# Creates a new `AtomicFixnum` with the given initial value.
|
11
11
|
#
|
12
12
|
# @param [Fixnum] initial the initial value
|
13
13
|
# @raise [ArgumentError] if the initial value is not a `Fixnum`
|
14
14
|
|
15
|
-
# @!macro
|
15
|
+
# @!macro atomic_fixnum_method_value_get
|
16
16
|
#
|
17
17
|
# Retrieves the current `Fixnum` value.
|
18
18
|
#
|
19
19
|
# @return [Fixnum] the current value
|
20
20
|
|
21
|
-
# @!macro
|
21
|
+
# @!macro atomic_fixnum_method_value_set
|
22
22
|
#
|
23
23
|
# Explicitly sets the value.
|
24
24
|
#
|
@@ -28,7 +28,7 @@ module Concurrent
|
|
28
28
|
#
|
29
29
|
# @raise [ArgumentError] if the new value is not a `Fixnum`
|
30
30
|
|
31
|
-
# @!macro
|
31
|
+
# @!macro atomic_fixnum_method_increment
|
32
32
|
#
|
33
33
|
# Increases the current value by the given amount (defaults to 1).
|
34
34
|
#
|
@@ -36,7 +36,7 @@ module Concurrent
|
|
36
36
|
#
|
37
37
|
# @return [Fixnum] the current value after incrementation
|
38
38
|
|
39
|
-
# @!macro
|
39
|
+
# @!macro atomic_fixnum_method_decrement
|
40
40
|
#
|
41
41
|
# Decreases the current value by the given amount (defaults to 1).
|
42
42
|
#
|
@@ -44,7 +44,7 @@ module Concurrent
|
|
44
44
|
#
|
45
45
|
# @return [Fixnum] the current value after decrementation
|
46
46
|
|
47
|
-
# @!macro
|
47
|
+
# @!macro atomic_fixnum_method_compare_and_set
|
48
48
|
#
|
49
49
|
# Atomically sets the value to the given updated value if the current
|
50
50
|
# value == the expected value.
|
@@ -52,9 +52,9 @@ module Concurrent
|
|
52
52
|
# @param [Fixnum] expect the expected value
|
53
53
|
# @param [Fixnum] update the new value
|
54
54
|
#
|
55
|
-
# @return [
|
55
|
+
# @return [Boolean] true if the value was updated else false
|
56
56
|
|
57
|
-
# @!macro
|
57
|
+
# @!macro atomic_fixnum_method_update
|
58
58
|
#
|
59
59
|
# Pass the current value to the given block, replacing it
|
60
60
|
# with the block's result. May retry if the value changes
|
@@ -68,7 +68,7 @@ module Concurrent
|
|
68
68
|
|
69
69
|
###################################################################
|
70
70
|
|
71
|
-
# @!macro
|
71
|
+
# @!macro atomic_fixnum_public_api
|
72
72
|
#
|
73
73
|
# @!method initialize(initial = 0)
|
74
74
|
# @!macro atomic_fixnum_method_initialize
|
@@ -79,10 +79,10 @@ module Concurrent
|
|
79
79
|
# @!method value=(value)
|
80
80
|
# @!macro atomic_fixnum_method_value_set
|
81
81
|
#
|
82
|
-
# @!method increment
|
82
|
+
# @!method increment(delta = 1)
|
83
83
|
# @!macro atomic_fixnum_method_increment
|
84
84
|
#
|
85
|
-
# @!method decrement
|
85
|
+
# @!method decrement(delta = 1)
|
86
86
|
# @!macro atomic_fixnum_method_decrement
|
87
87
|
#
|
88
88
|
# @!method compare_and_set(expect, update)
|
@@ -105,7 +105,7 @@ module Concurrent
|
|
105
105
|
end
|
106
106
|
private_constant :AtomicFixnumImplementation
|
107
107
|
|
108
|
-
# @!macro
|
108
|
+
# @!macro atomic_fixnum
|
109
109
|
#
|
110
110
|
# A numeric value that can be updated atomically. Reads and writes to an atomic
|
111
111
|
# fixnum and thread-safe and guaranteed to succeed. Reads and writes may block
|
@@ -113,17 +113,21 @@ module Concurrent
|
|
113
113
|
#
|
114
114
|
# @!macro thread_safe_variable_comparison
|
115
115
|
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
116
|
+
# Performance:
|
117
|
+
#
|
118
|
+
# ```
|
119
|
+
# Testing with ruby 2.1.2
|
120
|
+
# Testing with Concurrent::MutexAtomicFixnum...
|
121
|
+
# 3.130000 0.000000 3.130000 ( 3.136505)
|
122
|
+
# Testing with Concurrent::CAtomicFixnum...
|
123
|
+
# 0.790000 0.000000 0.790000 ( 0.785550)
|
121
124
|
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
125
|
+
# Testing with jruby 1.9.3
|
126
|
+
# Testing with Concurrent::MutexAtomicFixnum...
|
127
|
+
# 5.460000 2.460000 7.920000 ( 3.715000)
|
128
|
+
# Testing with Concurrent::JavaAtomicFixnum...
|
129
|
+
# 4.520000 0.030000 4.550000 ( 1.187000)
|
130
|
+
# ```
|
127
131
|
#
|
128
132
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong
|
129
133
|
#
|
@@ -131,7 +135,7 @@ module Concurrent
|
|
131
135
|
class AtomicFixnum < AtomicFixnumImplementation
|
132
136
|
# @return [String] Short string representation.
|
133
137
|
def to_s
|
134
|
-
format '
|
138
|
+
format '%s value:%s>', super[0..-2], value
|
135
139
|
end
|
136
140
|
|
137
141
|
alias_method :inspect, :to_s
|