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.
Files changed (107) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +42 -0
  3. data/Gemfile +39 -0
  4. data/{LICENSE.txt → LICENSE.md} +2 -0
  5. data/README.md +203 -105
  6. data/Rakefile +278 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +304 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent-ruby.rb +1 -0
  23. data/lib/concurrent.rb +24 -20
  24. data/lib/concurrent/agent.rb +7 -7
  25. data/lib/concurrent/array.rb +59 -32
  26. data/lib/concurrent/async.rb +4 -4
  27. data/lib/concurrent/atom.rb +9 -9
  28. data/lib/concurrent/atomic/atomic_boolean.rb +24 -20
  29. data/lib/concurrent/atomic/atomic_fixnum.rb +27 -23
  30. data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
  31. data/lib/concurrent/atomic/atomic_reference.rb +176 -33
  32. data/lib/concurrent/atomic/count_down_latch.rb +6 -6
  33. data/lib/concurrent/atomic/cyclic_barrier.rb +1 -1
  34. data/lib/concurrent/atomic/event.rb +1 -1
  35. data/lib/concurrent/atomic/java_count_down_latch.rb +6 -5
  36. data/lib/concurrent/atomic/mutex_count_down_latch.rb +1 -0
  37. data/lib/concurrent/atomic/read_write_lock.rb +2 -1
  38. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
  39. data/lib/concurrent/atomic/semaphore.rb +8 -8
  40. data/lib/concurrent/atomic/thread_local_var.rb +7 -7
  41. data/lib/concurrent/atomic_reference/mutex_atomic.rb +3 -8
  42. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +1 -1
  43. data/lib/concurrent/atomics.rb +0 -43
  44. data/lib/concurrent/collection/lock_free_stack.rb +127 -0
  45. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +3 -3
  46. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +1 -2
  47. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +29 -29
  48. data/lib/concurrent/concern/dereferenceable.rb +1 -1
  49. data/lib/concurrent/concern/logging.rb +6 -1
  50. data/lib/concurrent/concern/observable.rb +7 -7
  51. data/lib/concurrent/concurrent_ruby.jar +0 -0
  52. data/lib/concurrent/configuration.rb +1 -6
  53. data/lib/concurrent/constants.rb +1 -1
  54. data/lib/concurrent/dataflow.rb +2 -1
  55. data/lib/concurrent/delay.rb +9 -7
  56. data/lib/concurrent/exchanger.rb +13 -21
  57. data/lib/concurrent/executor/abstract_executor_service.rb +2 -2
  58. data/lib/concurrent/executor/cached_thread_pool.rb +1 -1
  59. data/lib/concurrent/executor/executor_service.rb +15 -15
  60. data/lib/concurrent/executor/fixed_thread_pool.rb +18 -18
  61. data/lib/concurrent/executor/java_thread_pool_executor.rb +10 -7
  62. data/lib/concurrent/executor/single_thread_executor.rb +2 -2
  63. data/lib/concurrent/executor/thread_pool_executor.rb +6 -6
  64. data/lib/concurrent/executor/timer_set.rb +1 -1
  65. data/lib/concurrent/future.rb +4 -1
  66. data/lib/concurrent/hash.rb +53 -30
  67. data/lib/concurrent/ivar.rb +5 -6
  68. data/lib/concurrent/map.rb +20 -25
  69. data/lib/concurrent/maybe.rb +1 -1
  70. data/lib/concurrent/mutable_struct.rb +15 -14
  71. data/lib/concurrent/mvar.rb +2 -2
  72. data/lib/concurrent/promise.rb +53 -21
  73. data/lib/concurrent/promises.rb +1938 -0
  74. data/lib/concurrent/re_include.rb +58 -0
  75. data/lib/concurrent/set.rb +66 -0
  76. data/lib/concurrent/settable_struct.rb +1 -0
  77. data/lib/concurrent/synchronization.rb +4 -5
  78. data/lib/concurrent/synchronization/abstract_lockable_object.rb +5 -5
  79. data/lib/concurrent/synchronization/abstract_struct.rb +6 -4
  80. data/lib/concurrent/synchronization/lockable_object.rb +6 -6
  81. data/lib/concurrent/synchronization/{mri_lockable_object.rb → mutex_lockable_object.rb} +19 -14
  82. data/lib/concurrent/synchronization/object.rb +8 -4
  83. data/lib/concurrent/synchronization/truffleruby_object.rb +46 -0
  84. data/lib/concurrent/synchronization/volatile.rb +11 -9
  85. data/lib/concurrent/thread_safe/util/data_structures.rb +55 -0
  86. data/lib/concurrent/thread_safe/util/striped64.rb +9 -4
  87. data/lib/concurrent/timer_task.rb +5 -2
  88. data/lib/concurrent/tuple.rb +1 -1
  89. data/lib/concurrent/tvar.rb +2 -2
  90. data/lib/concurrent/utility/at_exit.rb +1 -1
  91. data/lib/concurrent/utility/engine.rb +2 -2
  92. data/lib/concurrent/utility/monotonic_time.rb +3 -3
  93. data/lib/concurrent/utility/native_extension_loader.rb +31 -33
  94. data/lib/concurrent/utility/processor_counter.rb +0 -2
  95. data/lib/concurrent/version.rb +2 -2
  96. metadata +35 -21
  97. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  98. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  99. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  100. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  101. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  102. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  103. data/lib/concurrent/edge.rb +0 -26
  104. data/lib/concurrent/lazy_register.rb +0 -81
  105. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  106. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  107. 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"
@@ -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 [new] internal_implementation_note
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 [new] monotonic_clock_warning
46
+ # @!macro monotonic_clock_warning
44
47
  #
45
- # @note Time calculations one all platforms and languages are sensitive to
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 [new] copy_options
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 [attach] deref_options
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 [attach] executor_and_deref_options
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: `:task` returns the global task pool,
113
- # `:operation` returns the global operation pool, and `:immediate` returns a new
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
- # Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
118
- # F#, C#, Java, and classic concurrency patterns.
120
+ # @!macro warn.edge
121
+ # @api Edge
122
+ # @note **Edge Features** are under active development and may change frequently.
119
123
  #
120
- # The design goals of this gem are:
121
- #
122
- # * Stay true to the spirit of the languages providing inspiration
123
- # * But implement in a way that makes sense for Ruby
124
- # * Keep the semantics as idiomatic Ruby as possible
125
- # * Support features that make sense in Ruby
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
@@ -129,7 +129,7 @@ module Concurrent
129
129
  # end
130
130
  # ```
131
131
  #
132
- # @!macro [new] agent_await_warning
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 [attach] agent_send
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 [attach] send_return
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 [attach] send_bang_return_and_raise
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 {#send_off}
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 {#restart}
400
+ # @see #restart
401
401
  def failed?
402
402
  !@error.value.nil?
403
403
  end
@@ -2,38 +2,65 @@ require 'concurrent/utility/engine'
2
2
  require 'concurrent/thread_safe/util'
3
3
 
4
4
  module Concurrent
5
- if Concurrent.on_cruby?
6
-
7
- # Because MRI never runs code in parallel, the existing
8
- # non-thread-safe structures should usually work fine.
9
-
10
- # @!macro [attach] concurrent_array
11
- #
12
- # A thread-safe subclass of Array. This version locks against the object
13
- # itself for every method call, ensuring only one thread can be reading
14
- # or writing at a time. This includes iteration methods like `#each`.
15
- #
16
- # @see http://ruby-doc.org/core-2.2.0/Array.html Ruby standard library `Array`
17
- class Array < ::Array;
18
- end
19
-
20
- elsif Concurrent.on_jruby?
21
- require 'jruby/synchronized'
22
-
23
- # @!macro concurrent_array
24
- class Array < ::Array
25
- include JRuby::Synchronized
26
- end
27
-
28
- elsif Concurrent.on_rbx? || Concurrent.on_truffle?
29
- require 'monitor'
30
- require 'concurrent/thread_safe/util/array_hash_rbx'
31
-
32
- # @!macro concurrent_array
33
- class Array < ::Array
34
- end
35
-
36
- ThreadSafe::Util.make_synchronized_on_rbx Array
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