concurrent-ruby 1.0.5 → 1.1.0.pre1

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.
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