concurrent-ruby 1.0.5 → 1.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +42 -0
- data/Gemfile +39 -0
- data/{LICENSE.txt → LICENSE.md} +2 -0
- data/README.md +203 -105
- data/Rakefile +278 -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 +159 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +304 -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-ruby.rb +1 -0
- data/lib/concurrent.rb +24 -20
- data/lib/concurrent/agent.rb +7 -7
- data/lib/concurrent/array.rb +59 -32
- data/lib/concurrent/async.rb +4 -4
- data/lib/concurrent/atom.rb +9 -9
- data/lib/concurrent/atomic/atomic_boolean.rb +24 -20
- data/lib/concurrent/atomic/atomic_fixnum.rb +27 -23
- data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent/atomic/atomic_reference.rb +176 -33
- data/lib/concurrent/atomic/count_down_latch.rb +6 -6
- data/lib/concurrent/atomic/cyclic_barrier.rb +1 -1
- data/lib/concurrent/atomic/event.rb +1 -1
- data/lib/concurrent/atomic/java_count_down_latch.rb +6 -5
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +1 -0
- data/lib/concurrent/atomic/read_write_lock.rb +2 -1
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
- data/lib/concurrent/atomic/semaphore.rb +8 -8
- data/lib/concurrent/atomic/thread_local_var.rb +7 -7
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +3 -8
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +1 -1
- data/lib/concurrent/atomics.rb +0 -43
- data/lib/concurrent/collection/lock_free_stack.rb +127 -0
- data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +3 -3
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +1 -2
- data/lib/concurrent/collection/non_concurrent_priority_queue.rb +29 -29
- data/lib/concurrent/concern/dereferenceable.rb +1 -1
- data/lib/concurrent/concern/logging.rb +6 -1
- data/lib/concurrent/concern/observable.rb +7 -7
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/configuration.rb +1 -6
- data/lib/concurrent/constants.rb +1 -1
- data/lib/concurrent/dataflow.rb +2 -1
- data/lib/concurrent/delay.rb +9 -7
- data/lib/concurrent/exchanger.rb +13 -21
- data/lib/concurrent/executor/abstract_executor_service.rb +2 -2
- data/lib/concurrent/executor/cached_thread_pool.rb +1 -1
- data/lib/concurrent/executor/executor_service.rb +15 -15
- data/lib/concurrent/executor/fixed_thread_pool.rb +18 -18
- data/lib/concurrent/executor/java_thread_pool_executor.rb +10 -7
- data/lib/concurrent/executor/single_thread_executor.rb +2 -2
- data/lib/concurrent/executor/thread_pool_executor.rb +6 -6
- data/lib/concurrent/executor/timer_set.rb +1 -1
- data/lib/concurrent/future.rb +4 -1
- data/lib/concurrent/hash.rb +53 -30
- data/lib/concurrent/ivar.rb +5 -6
- data/lib/concurrent/map.rb +20 -25
- data/lib/concurrent/maybe.rb +1 -1
- data/lib/concurrent/mutable_struct.rb +15 -14
- data/lib/concurrent/mvar.rb +2 -2
- data/lib/concurrent/promise.rb +53 -21
- data/lib/concurrent/promises.rb +1938 -0
- data/lib/concurrent/re_include.rb +58 -0
- data/lib/concurrent/set.rb +66 -0
- data/lib/concurrent/settable_struct.rb +1 -0
- data/lib/concurrent/synchronization.rb +4 -5
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +5 -5
- data/lib/concurrent/synchronization/abstract_struct.rb +6 -4
- data/lib/concurrent/synchronization/lockable_object.rb +6 -6
- data/lib/concurrent/synchronization/{mri_lockable_object.rb → mutex_lockable_object.rb} +19 -14
- data/lib/concurrent/synchronization/object.rb +8 -4
- data/lib/concurrent/synchronization/truffleruby_object.rb +46 -0
- data/lib/concurrent/synchronization/volatile.rb +11 -9
- data/lib/concurrent/thread_safe/util/data_structures.rb +55 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +9 -4
- data/lib/concurrent/timer_task.rb +5 -2
- data/lib/concurrent/tuple.rb +1 -1
- data/lib/concurrent/tvar.rb +2 -2
- data/lib/concurrent/utility/at_exit.rb +1 -1
- data/lib/concurrent/utility/engine.rb +2 -2
- data/lib/concurrent/utility/monotonic_time.rb +3 -3
- data/lib/concurrent/utility/native_extension_loader.rb +31 -33
- data/lib/concurrent/utility/processor_counter.rb +0 -2
- data/lib/concurrent/version.rb +2 -2
- metadata +35 -21
- 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/edge.rb +0 -26
- data/lib/concurrent/lazy_register.rb +0 -81
- 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
@@ -0,0 +1,199 @@
|
|
1
|
+
/*
|
2
|
+
* Written by Doug Lea with assistance from members of JCP JSR-166
|
3
|
+
* Expert Group and released to the public domain, as explained at
|
4
|
+
* http://creativecommons.org/publicdomain/zero/1.0/
|
5
|
+
*/
|
6
|
+
|
7
|
+
// This is based on 1.16 version
|
8
|
+
|
9
|
+
package com.concurrent_ruby.ext.jsr166y;
|
10
|
+
|
11
|
+
import java.util.Random;
|
12
|
+
|
13
|
+
/**
|
14
|
+
* A random number generator isolated to the current thread. Like the
|
15
|
+
* global {@link java.util.Random} generator used by the {@link
|
16
|
+
* java.lang.Math} class, a {@code ThreadLocalRandom} is initialized
|
17
|
+
* with an internally generated seed that may not otherwise be
|
18
|
+
* modified. When applicable, use of {@code ThreadLocalRandom} rather
|
19
|
+
* than shared {@code Random} objects in concurrent programs will
|
20
|
+
* typically encounter much less overhead and contention. Use of
|
21
|
+
* {@code ThreadLocalRandom} is particularly appropriate when multiple
|
22
|
+
* tasks (for example, each a {@link ForkJoinTask}) use random numbers
|
23
|
+
* in parallel in thread pools.
|
24
|
+
*
|
25
|
+
* <p>Usages of this class should typically be of the form:
|
26
|
+
* {@code ThreadLocalRandom.current().nextX(...)} (where
|
27
|
+
* {@code X} is {@code Int}, {@code Long}, etc).
|
28
|
+
* When all usages are of this form, it is never possible to
|
29
|
+
* accidently share a {@code ThreadLocalRandom} across multiple threads.
|
30
|
+
*
|
31
|
+
* <p>This class also provides additional commonly used bounded random
|
32
|
+
* generation methods.
|
33
|
+
*
|
34
|
+
* @since 1.7
|
35
|
+
* @author Doug Lea
|
36
|
+
*/
|
37
|
+
public class ThreadLocalRandom extends Random {
|
38
|
+
// same constants as Random, but must be redeclared because private
|
39
|
+
private static final long multiplier = 0x5DEECE66DL;
|
40
|
+
private static final long addend = 0xBL;
|
41
|
+
private static final long mask = (1L << 48) - 1;
|
42
|
+
|
43
|
+
/**
|
44
|
+
* The random seed. We can't use super.seed.
|
45
|
+
*/
|
46
|
+
private long rnd;
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Initialization flag to permit calls to setSeed to succeed only
|
50
|
+
* while executing the Random constructor. We can't allow others
|
51
|
+
* since it would cause setting seed in one part of a program to
|
52
|
+
* unintentionally impact other usages by the thread.
|
53
|
+
*/
|
54
|
+
boolean initialized;
|
55
|
+
|
56
|
+
// Padding to help avoid memory contention among seed updates in
|
57
|
+
// different TLRs in the common case that they are located near
|
58
|
+
// each other.
|
59
|
+
private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
|
60
|
+
|
61
|
+
/**
|
62
|
+
* The actual ThreadLocal
|
63
|
+
*/
|
64
|
+
private static final ThreadLocal<ThreadLocalRandom> localRandom =
|
65
|
+
new ThreadLocal<ThreadLocalRandom>() {
|
66
|
+
protected ThreadLocalRandom initialValue() {
|
67
|
+
return new ThreadLocalRandom();
|
68
|
+
}
|
69
|
+
};
|
70
|
+
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Constructor called only by localRandom.initialValue.
|
74
|
+
*/
|
75
|
+
ThreadLocalRandom() {
|
76
|
+
super();
|
77
|
+
initialized = true;
|
78
|
+
}
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Returns the current thread's {@code ThreadLocalRandom}.
|
82
|
+
*
|
83
|
+
* @return the current thread's {@code ThreadLocalRandom}
|
84
|
+
*/
|
85
|
+
public static ThreadLocalRandom current() {
|
86
|
+
return localRandom.get();
|
87
|
+
}
|
88
|
+
|
89
|
+
/**
|
90
|
+
* Throws {@code UnsupportedOperationException}. Setting seeds in
|
91
|
+
* this generator is not supported.
|
92
|
+
*
|
93
|
+
* @throws UnsupportedOperationException always
|
94
|
+
*/
|
95
|
+
public void setSeed(long seed) {
|
96
|
+
if (initialized)
|
97
|
+
throw new UnsupportedOperationException();
|
98
|
+
rnd = (seed ^ multiplier) & mask;
|
99
|
+
}
|
100
|
+
|
101
|
+
protected int next(int bits) {
|
102
|
+
rnd = (rnd * multiplier + addend) & mask;
|
103
|
+
return (int) (rnd >>> (48-bits));
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Returns a pseudorandom, uniformly distributed value between the
|
108
|
+
* given least value (inclusive) and bound (exclusive).
|
109
|
+
*
|
110
|
+
* @param least the least value returned
|
111
|
+
* @param bound the upper bound (exclusive)
|
112
|
+
* @throws IllegalArgumentException if least greater than or equal
|
113
|
+
* to bound
|
114
|
+
* @return the next value
|
115
|
+
*/
|
116
|
+
public int nextInt(int least, int bound) {
|
117
|
+
if (least >= bound)
|
118
|
+
throw new IllegalArgumentException();
|
119
|
+
return nextInt(bound - least) + least;
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* Returns a pseudorandom, uniformly distributed value
|
124
|
+
* between 0 (inclusive) and the specified value (exclusive).
|
125
|
+
*
|
126
|
+
* @param n the bound on the random number to be returned. Must be
|
127
|
+
* positive.
|
128
|
+
* @return the next value
|
129
|
+
* @throws IllegalArgumentException if n is not positive
|
130
|
+
*/
|
131
|
+
public long nextLong(long n) {
|
132
|
+
if (n <= 0)
|
133
|
+
throw new IllegalArgumentException("n must be positive");
|
134
|
+
// Divide n by two until small enough for nextInt. On each
|
135
|
+
// iteration (at most 31 of them but usually much less),
|
136
|
+
// randomly choose both whether to include high bit in result
|
137
|
+
// (offset) and whether to continue with the lower vs upper
|
138
|
+
// half (which makes a difference only if odd).
|
139
|
+
long offset = 0;
|
140
|
+
while (n >= Integer.MAX_VALUE) {
|
141
|
+
int bits = next(2);
|
142
|
+
long half = n >>> 1;
|
143
|
+
long nextn = ((bits & 2) == 0) ? half : n - half;
|
144
|
+
if ((bits & 1) == 0)
|
145
|
+
offset += n - nextn;
|
146
|
+
n = nextn;
|
147
|
+
}
|
148
|
+
return offset + nextInt((int) n);
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Returns a pseudorandom, uniformly distributed value between the
|
153
|
+
* given least value (inclusive) and bound (exclusive).
|
154
|
+
*
|
155
|
+
* @param least the least value returned
|
156
|
+
* @param bound the upper bound (exclusive)
|
157
|
+
* @return the next value
|
158
|
+
* @throws IllegalArgumentException if least greater than or equal
|
159
|
+
* to bound
|
160
|
+
*/
|
161
|
+
public long nextLong(long least, long bound) {
|
162
|
+
if (least >= bound)
|
163
|
+
throw new IllegalArgumentException();
|
164
|
+
return nextLong(bound - least) + least;
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* Returns a pseudorandom, uniformly distributed {@code double} value
|
169
|
+
* between 0 (inclusive) and the specified value (exclusive).
|
170
|
+
*
|
171
|
+
* @param n the bound on the random number to be returned. Must be
|
172
|
+
* positive.
|
173
|
+
* @return the next value
|
174
|
+
* @throws IllegalArgumentException if n is not positive
|
175
|
+
*/
|
176
|
+
public double nextDouble(double n) {
|
177
|
+
if (n <= 0)
|
178
|
+
throw new IllegalArgumentException("n must be positive");
|
179
|
+
return nextDouble() * n;
|
180
|
+
}
|
181
|
+
|
182
|
+
/**
|
183
|
+
* Returns a pseudorandom, uniformly distributed value between the
|
184
|
+
* given least value (inclusive) and bound (exclusive).
|
185
|
+
*
|
186
|
+
* @param least the least value returned
|
187
|
+
* @param bound the upper bound (exclusive)
|
188
|
+
* @return the next value
|
189
|
+
* @throws IllegalArgumentException if least greater than or equal
|
190
|
+
* to bound
|
191
|
+
*/
|
192
|
+
public double nextDouble(double least, double bound) {
|
193
|
+
if (least >= bound)
|
194
|
+
throw new IllegalArgumentException();
|
195
|
+
return nextDouble() * (bound - least) + least;
|
196
|
+
}
|
197
|
+
|
198
|
+
private static final long serialVersionUID = -5851777807851030925L;
|
199
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "./concurrent"
|
data/lib/concurrent.rb
CHANGED
@@ -7,11 +7,13 @@ require 'concurrent/atomics'
|
|
7
7
|
require 'concurrent/executors'
|
8
8
|
require 'concurrent/synchronization'
|
9
9
|
|
10
|
+
require 'concurrent/atomic/atomic_markable_reference'
|
10
11
|
require 'concurrent/atomic/atomic_reference'
|
11
12
|
require 'concurrent/agent'
|
12
13
|
require 'concurrent/atom'
|
13
14
|
require 'concurrent/array'
|
14
15
|
require 'concurrent/hash'
|
16
|
+
require 'concurrent/set'
|
15
17
|
require 'concurrent/map'
|
16
18
|
require 'concurrent/tuple'
|
17
19
|
require 'concurrent/async'
|
@@ -29,20 +31,21 @@ require 'concurrent/scheduled_task'
|
|
29
31
|
require 'concurrent/settable_struct'
|
30
32
|
require 'concurrent/timer_task'
|
31
33
|
require 'concurrent/tvar'
|
34
|
+
require 'concurrent/promises'
|
32
35
|
|
33
36
|
require 'concurrent/thread_safe/synchronized_delegator'
|
34
37
|
require 'concurrent/thread_safe/util'
|
35
38
|
|
36
39
|
require 'concurrent/options'
|
37
40
|
|
38
|
-
# @!macro
|
41
|
+
# @!macro internal_implementation_note
|
39
42
|
#
|
40
43
|
# @note **Private Implementation:** This abstraction is a private, internal
|
41
44
|
# implementation detail. It should never be used directly.
|
42
45
|
|
43
|
-
# @!macro
|
46
|
+
# @!macro monotonic_clock_warning
|
44
47
|
#
|
45
|
-
# @note Time calculations
|
48
|
+
# @note Time calculations on all platforms and languages are sensitive to
|
46
49
|
# changes to the system clock. To alleviate the potential problems
|
47
50
|
# associated with changing the system clock while an application is running,
|
48
51
|
# most modern operating systems provide a monotonic clock that operates
|
@@ -58,7 +61,7 @@ require 'concurrent/options'
|
|
58
61
|
#
|
59
62
|
# @see http://linux.die.net/man/3/clock_gettime Linux clock_gettime(3)
|
60
63
|
|
61
|
-
# @!macro
|
64
|
+
# @!macro copy_options
|
62
65
|
#
|
63
66
|
# ## Copy Options
|
64
67
|
#
|
@@ -94,7 +97,7 @@ require 'concurrent/options'
|
|
94
97
|
# as close to the behavior of a "pure" functional language (like Erlang, Clojure,
|
95
98
|
# or Haskell) as we are likely to get in Ruby.
|
96
99
|
|
97
|
-
# @!macro
|
100
|
+
# @!macro deref_options
|
98
101
|
#
|
99
102
|
# @option opts [Boolean] :dup_on_deref (false) Call `#dup` before
|
100
103
|
# returning the data from {#value}
|
@@ -104,27 +107,28 @@ require 'concurrent/options'
|
|
104
107
|
# method, call the given proc passing the internal value as the sole
|
105
108
|
# argument then return the new value returned from the proc.
|
106
109
|
|
107
|
-
# @!macro
|
110
|
+
# @!macro executor_and_deref_options
|
108
111
|
#
|
109
112
|
# @param [Hash] opts the options used to define the behavior at update and deref
|
110
113
|
# and to specify the executor on which to perform actions
|
111
114
|
# @option opts [Executor] :executor when set use the given `Executor` instance.
|
112
|
-
# Three special values are also supported: `:
|
113
|
-
# `:
|
114
|
-
# `ImmediateExecutor` object.
|
115
|
+
# Three special values are also supported: `:io` returns the global pool for
|
116
|
+
# long, blocking (IO) tasks, `:fast` returns the global pool for short, fast
|
117
|
+
# operations, and `:immediate` returns the global `ImmediateExecutor` object.
|
115
118
|
# @!macro deref_options
|
116
119
|
|
117
|
-
#
|
118
|
-
#
|
120
|
+
# @!macro warn.edge
|
121
|
+
# @api Edge
|
122
|
+
# @note **Edge Features** are under active development and may change frequently.
|
119
123
|
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
# * Exclude features that don't make sense in Ruby
|
127
|
-
# * Be small, lean, and loosely coupled
|
128
|
-
module Concurrent
|
124
|
+
# - Deprecations are not added before incompatible changes.
|
125
|
+
# - Edge version: _major_ is always 0, _minor_ bump means incompatible change,
|
126
|
+
# _patch_ bump means compatible change.
|
127
|
+
# - Edge features may also lack tests and documentation.
|
128
|
+
# - Features developed in `concurrent-ruby-edge` are expected to move
|
129
|
+
# to `concurrent-ruby` when finalised.
|
129
130
|
|
131
|
+
|
132
|
+
# {include:file:README.md}
|
133
|
+
module Concurrent
|
130
134
|
end
|
data/lib/concurrent/agent.rb
CHANGED
@@ -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
|
data/lib/concurrent/array.rb
CHANGED
@@ -2,38 +2,65 @@ require 'concurrent/utility/engine'
|
|
2
2
|
require 'concurrent/thread_safe/util'
|
3
3
|
|
4
4
|
module Concurrent
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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-2.2.0/Array.html Ruby standard library `Array`
|
20
|
+
|
21
|
+
# @!macro internal_implementation_note
|
22
|
+
ArrayImplementation = case
|
23
|
+
when Concurrent.on_cruby?
|
24
|
+
# Because MRI never runs code in parallel, the existing
|
25
|
+
# non-thread-safe structures should usually work fine.
|
26
|
+
::Array
|
27
|
+
|
28
|
+
when Concurrent.on_jruby?
|
29
|
+
require 'jruby/synchronized'
|
30
|
+
|
31
|
+
class JRubyArray < ::Array
|
32
|
+
include JRuby::Synchronized
|
33
|
+
end
|
34
|
+
JRubyArray
|
35
|
+
|
36
|
+
when Concurrent.on_rbx?
|
37
|
+
require 'monitor'
|
38
|
+
require 'concurrent/thread_safe/util/data_structures'
|
39
|
+
|
40
|
+
class RbxArray < ::Array
|
41
|
+
end
|
42
|
+
|
43
|
+
ThreadSafe::Util.make_synchronized_on_rbx RbxArray
|
44
|
+
RbxArray
|
45
|
+
|
46
|
+
when Concurrent.on_truffleruby?
|
47
|
+
require 'concurrent/thread_safe/util/data_structures'
|
48
|
+
|
49
|
+
class TruffleRubyArray < ::Array
|
50
|
+
end
|
51
|
+
|
52
|
+
ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubyArray
|
53
|
+
TruffleRubyArray
|
54
|
+
|
55
|
+
else
|
56
|
+
warn 'Possibly unsupported Ruby implementation'
|
57
|
+
::Array
|
58
|
+
end
|
59
|
+
private_constant :ArrayImplementation
|
60
|
+
|
61
|
+
# @!macro concurrent_array
|
62
|
+
class Array < ArrayImplementation
|
37
63
|
end
|
64
|
+
|
38
65
|
end
|
39
66
|
|