concurrent-ruby 0.9.2-java → 1.0.0-java

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -1
  3. data/README.md +86 -120
  4. data/lib/concurrent.rb +14 -5
  5. data/lib/concurrent/agent.rb +587 -0
  6. data/lib/concurrent/array.rb +39 -0
  7. data/lib/concurrent/async.rb +296 -149
  8. data/lib/concurrent/atom.rb +135 -45
  9. data/lib/concurrent/atomic/abstract_thread_local_var.rb +38 -0
  10. data/lib/concurrent/atomic/atomic_boolean.rb +83 -118
  11. data/lib/concurrent/atomic/atomic_fixnum.rb +101 -163
  12. data/lib/concurrent/atomic/atomic_reference.rb +1 -8
  13. data/lib/concurrent/atomic/count_down_latch.rb +62 -103
  14. data/lib/concurrent/atomic/cyclic_barrier.rb +3 -1
  15. data/lib/concurrent/atomic/event.rb +1 -1
  16. data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
  17. data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
  18. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
  19. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
  20. data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
  21. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  22. data/lib/concurrent/atomic/read_write_lock.rb +5 -4
  23. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
  24. data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
  25. data/lib/concurrent/atomic/semaphore.rb +84 -178
  26. data/lib/concurrent/atomic/thread_local_var.rb +65 -294
  27. data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -0
  28. data/lib/concurrent/atomic_reference/jruby.rb +1 -1
  29. data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
  30. data/lib/concurrent/atomic_reference/ruby.rb +1 -1
  31. data/lib/concurrent/atomics.rb +7 -37
  32. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +7 -15
  33. data/lib/concurrent/collection/copy_on_write_observer_set.rb +7 -15
  34. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  35. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  36. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  37. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +144 -0
  38. data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
  39. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  40. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  41. data/lib/concurrent/concern/dereferenceable.rb +9 -24
  42. data/lib/concurrent/concern/logging.rb +1 -1
  43. data/lib/concurrent/concern/obligation.rb +11 -20
  44. data/lib/concurrent/concern/observable.rb +38 -13
  45. data/lib/concurrent/configuration.rb +23 -152
  46. data/lib/concurrent/constants.rb +8 -0
  47. data/lib/concurrent/delay.rb +14 -12
  48. data/lib/concurrent/exchanger.rb +339 -41
  49. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  50. data/lib/concurrent/executor/executor_service.rb +23 -359
  51. data/lib/concurrent/executor/immediate_executor.rb +3 -2
  52. data/lib/concurrent/executor/java_executor_service.rb +100 -0
  53. data/lib/concurrent/executor/java_single_thread_executor.rb +3 -3
  54. data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
  55. data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
  56. data/lib/concurrent/executor/ruby_single_thread_executor.rb +10 -66
  57. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +25 -22
  58. data/lib/concurrent/executor/safe_task_executor.rb +6 -7
  59. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  60. data/lib/concurrent/executor/serialized_execution.rb +10 -33
  61. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  62. data/lib/concurrent/executor/simple_executor_service.rb +1 -10
  63. data/lib/concurrent/executor/single_thread_executor.rb +20 -10
  64. data/lib/concurrent/executor/timer_set.rb +8 -10
  65. data/lib/concurrent/executors.rb +12 -2
  66. data/lib/concurrent/future.rb +6 -4
  67. data/lib/concurrent/hash.rb +35 -0
  68. data/lib/concurrent/immutable_struct.rb +5 -1
  69. data/lib/concurrent/ivar.rb +12 -16
  70. data/lib/concurrent/lazy_register.rb +11 -8
  71. data/lib/concurrent/map.rb +180 -0
  72. data/lib/concurrent/maybe.rb +6 -3
  73. data/lib/concurrent/mutable_struct.rb +7 -6
  74. data/lib/concurrent/mvar.rb +26 -2
  75. data/lib/concurrent/{executor/executor.rb → options.rb} +5 -29
  76. data/lib/concurrent/promise.rb +7 -5
  77. data/lib/concurrent/scheduled_task.rb +13 -71
  78. data/lib/concurrent/settable_struct.rb +5 -4
  79. data/lib/concurrent/synchronization.rb +15 -3
  80. data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  81. data/lib/concurrent/synchronization/abstract_object.rb +7 -146
  82. data/lib/concurrent/synchronization/abstract_struct.rb +2 -3
  83. data/lib/concurrent/synchronization/condition.rb +6 -4
  84. data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  85. data/lib/concurrent/synchronization/jruby_object.rb +44 -0
  86. data/lib/concurrent/synchronization/lock.rb +3 -2
  87. data/lib/concurrent/synchronization/lockable_object.rb +72 -0
  88. data/lib/concurrent/synchronization/mri_lockable_object.rb +71 -0
  89. data/lib/concurrent/synchronization/mri_object.rb +43 -0
  90. data/lib/concurrent/synchronization/object.rb +140 -73
  91. data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
  92. data/lib/concurrent/synchronization/rbx_object.rb +30 -73
  93. data/lib/concurrent/synchronization/volatile.rb +34 -0
  94. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  95. data/lib/concurrent/thread_safe/util.rb +14 -0
  96. data/lib/concurrent/thread_safe/util/adder.rb +74 -0
  97. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +30 -0
  98. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  99. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  100. data/lib/concurrent/thread_safe/util/striped64.rb +241 -0
  101. data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
  102. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  103. data/lib/concurrent/timer_task.rb +3 -4
  104. data/lib/concurrent/tuple.rb +86 -0
  105. data/lib/concurrent/tvar.rb +5 -1
  106. data/lib/concurrent/utility/at_exit.rb +1 -1
  107. data/lib/concurrent/utility/engine.rb +4 -0
  108. data/lib/concurrent/utility/monotonic_time.rb +3 -4
  109. data/lib/concurrent/utility/native_extension_loader.rb +50 -30
  110. data/lib/concurrent/version.rb +2 -2
  111. data/lib/concurrent_ruby_ext.jar +0 -0
  112. metadata +47 -12
  113. data/lib/concurrent/atomic/condition.rb +0 -78
  114. data/lib/concurrent/collection/priority_queue.rb +0 -360
  115. data/lib/concurrent/synchronization/java_object.rb +0 -34
  116. data/lib/concurrent/synchronization/monitor_object.rb +0 -27
  117. data/lib/concurrent/synchronization/mutex_object.rb +0 -43
  118. data/lib/concurrent/utilities.rb +0 -5
  119. data/lib/concurrent/utility/timeout.rb +0 -39
  120. data/lib/concurrent/utility/timer.rb +0 -26
  121. data/lib/concurrent_ruby.rb +0 -2
@@ -1,12 +1,75 @@
1
- require 'thread'
1
+ require 'concurrent/atomic/ruby_thread_local_var'
2
+ require 'concurrent/atomic/java_thread_local_var'
3
+ require 'concurrent/utility/engine'
2
4
 
3
5
  module Concurrent
4
6
 
7
+ ###################################################################
8
+
9
+ # @!macro [new] thread_local_var_method_initialize
10
+ #
11
+ # Creates a thread local variable.
12
+ #
13
+ # @param [Object] default the default value when otherwise unset
14
+
15
+ # @!macro [new] thread_local_var_method_get
16
+ #
17
+ # Returns the value in the current thread's copy of this thread-local variable.
18
+ #
19
+ # @return [Object] the current value
20
+
21
+ # @!macro [new] thread_local_var_method_set
22
+ #
23
+ # Sets the current thread's copy of this thread-local variable to the specified value.
24
+ #
25
+ # @param [Object] value the value to set
26
+ # @return [Object] the new value
27
+
28
+ # @!macro [new] thread_local_var_method_bind
29
+ #
30
+ # Bind the given value to thread local storage during
31
+ # execution of the given block.
32
+ #
33
+ # @param [Object] value the value to bind
34
+ # @yield the operation to be performed with the bound variable
35
+ # @return [Object] the value
36
+
37
+
38
+ ###################################################################
39
+
40
+ # @!macro [new] thread_local_var_public_api
41
+ #
42
+ # @!method initialize(default = nil)
43
+ # @!macro thread_local_var_method_initialize
44
+ #
45
+ # @!method value
46
+ # @!macro thread_local_var_method_get
47
+ #
48
+ # @!method value=(value)
49
+ # @!macro thread_local_var_method_set
50
+ #
51
+ # @!method bind(value, &block)
52
+ # @!macro thread_local_var_method_bind
53
+
54
+ ###################################################################
55
+
56
+ # @!visibility private
57
+ # @!macro internal_implementation_note
58
+ ThreadLocalVarImplementation = case
59
+ when Concurrent.on_jruby?
60
+ JavaThreadLocalVar
61
+ else
62
+ RubyThreadLocalVar
63
+ end
64
+ private_constant :ThreadLocalVarImplementation
65
+
5
66
  # @!macro [attach] thread_local_var
6
67
  #
7
68
  # A `ThreadLocalVar` is a variable where the value is different for each thread.
8
69
  # Each variable may have a default value, but when you modify the variable only
9
70
  # the current thread will ever see that change.
71
+ #
72
+ # @!macro thread_safe_variable_comparison
10
73
  #
11
74
  # @example
12
75
  # v = ThreadLocalVar.new(14)
@@ -33,299 +96,7 @@ module Concurrent
33
96
  #
34
97
  # @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal
35
98
  #
36
- # @!visibility private
37
- class AbstractThreadLocalVar
38
-
39
- # @!visibility private
40
- NIL_SENTINEL = Object.new
41
- private_constant :NIL_SENTINEL
42
-
43
- # @!macro [attach] thread_local_var_method_initialize
44
- #
45
- # Creates a thread local variable.
46
- #
47
- # @param [Object] default the default value when otherwise unset
48
- def initialize(default = nil)
49
- @default = default
50
- allocate_storage
51
- end
52
-
53
- # @!macro [attach] thread_local_var_method_get
54
- #
55
- # Returns the value in the current thread's copy of this thread-local variable.
56
- #
57
- # @return [Object] the current value
58
- def value
59
- raise NotImplementedError
60
- end
61
-
62
- # @!macro [attach] thread_local_var_method_set
63
- #
64
- # Sets the current thread's copy of this thread-local variable to the specified value.
65
- #
66
- # @param [Object] value the value to set
67
- # @return [Object] the new value
68
- def value=(value)
69
- raise NotImplementedError
70
- end
71
-
72
- # @!macro [attach] thread_local_var_method_bind
73
- #
74
- # Bind the given value to thread local storage during
75
- # execution of the given block.
76
- #
77
- # @param [Object] value the value to bind
78
- # @yield the operation to be performed with the bound variable
79
- # @return [Object] the value
80
- def bind(value, &block)
81
- raise NotImplementedError
82
- end
83
-
84
- protected
85
-
86
- # @!visibility private
87
- def allocate_storage
88
- raise NotImplementedError
89
- end
90
- end
91
-
92
- # @!visibility private
93
- # @!macro internal_implementation_note
94
- class RubyThreadLocalVar < AbstractThreadLocalVar
95
-
96
- # Each thread has a (lazily initialized) array of thread-local variable values
97
- # Each time a new thread-local var is created, we allocate an "index" for it
98
- # For example, if the allocated index is 1, that means slot #1 in EVERY
99
- # thread's thread-local array will be used for the value of that TLV
100
- #
101
- # The good thing about using a per-THREAD structure to hold values, rather
102
- # than a per-TLV structure, is that no synchronization is needed when
103
- # reading and writing those values (since the structure is only ever
104
- # accessed by a single thread)
105
- #
106
- # Of course, when a TLV is GC'd, 1) we need to recover its index for use
107
- # by other new TLVs (otherwise the thread-local arrays could get bigger
108
- # and bigger with time), and 2) we need to null out all the references
109
- # held in the now-unused slots (both to avoid blocking GC of those objects,
110
- # and also to prevent "stale" values from being passed on to a new TLV
111
- # when the index is reused)
112
- # Because we need to null out freed slots, we need to keep references to
113
- # ALL the thread-local arrays -- ARRAYS is for that
114
- # But when a Thread is GC'd, we need to drop the reference to its thread-local
115
- # array, so we don't leak memory
116
-
117
- # @!visibility private
118
- FREE = []
119
- LOCK = Mutex.new
120
- ARRAYS = {} # used as a hash set
121
- @@next = 0
122
- private_constant :FREE, :LOCK, :ARRAYS
123
-
124
- # @!macro [attach] thread_local_var_method_initialize
125
- #
126
- # Creates a thread local variable.
127
- #
128
- # @param [Object] default the default value when otherwise unset
129
- def initialize(default = nil)
130
- @default = default
131
- allocate_storage
132
- end
133
-
134
- # @!macro thread_local_var_method_get
135
- def value
136
- if array = get_threadlocal_array
137
- value = array[@index]
138
- if value.nil?
139
- @default
140
- elsif value.equal?(NIL_SENTINEL)
141
- nil
142
- else
143
- value
144
- end
145
- else
146
- @default
147
- end
148
- end
149
-
150
- # @!macro thread_local_var_method_set
151
- def value=(value)
152
- me = Thread.current
153
- # We could keep the thread-local arrays in a hash, keyed by Thread
154
- # But why? That would require locking
155
- # Using Ruby's built-in thread-local storage is faster
156
- unless array = get_threadlocal_array(me)
157
- array = set_threadlocal_array([], me)
158
- LOCK.synchronize { ARRAYS[array.object_id] = array }
159
- ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
160
- end
161
- array[@index] = (value.nil? ? NIL_SENTINEL : value)
162
- value
163
- end
164
-
165
- # @!macro thread_local_var_method_bind
166
- def bind(value, &block)
167
- if block_given?
168
- old_value = self.value
169
- begin
170
- self.value = value
171
- yield
172
- ensure
173
- self.value = old_value
174
- end
175
- end
176
- end
177
-
178
- protected
179
-
180
- # @!visibility private
181
- def allocate_storage
182
- @index = LOCK.synchronize do
183
- FREE.pop || begin
184
- result = @@next
185
- @@next += 1
186
- result
187
- end
188
- end
189
- ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index))
190
- end
191
-
192
- # @!visibility private
193
- def self.threadlocal_finalizer(index)
194
- proc do
195
- LOCK.synchronize do
196
- FREE.push(index)
197
- # The cost of GC'ing a TLV is linear in the number of threads using TLVs
198
- # But that is natural! More threads means more storage is used per TLV
199
- # So naturally more CPU time is required to free more storage
200
- ARRAYS.each_value do |array|
201
- array[index] = nil
202
- end
203
- end
204
- end
205
- end
206
-
207
- # @!visibility private
208
- def self.thread_finalizer(array)
209
- proc do
210
- LOCK.synchronize do
211
- # The thread which used this thread-local array is now gone
212
- # So don't hold onto a reference to the array (thus blocking GC)
213
- ARRAYS.delete(array.object_id)
214
- end
215
- end
216
- end
217
-
218
- private
219
-
220
- if Thread.instance_methods.include?(:thread_variable_get)
221
-
222
- def get_threadlocal_array(thread = Thread.current)
223
- thread.thread_variable_get(:__threadlocal_array__)
224
- end
225
-
226
- def set_threadlocal_array(array, thread = Thread.current)
227
- thread.thread_variable_set(:__threadlocal_array__, array)
228
- end
229
-
230
- else
231
-
232
- def get_threadlocal_array(thread = Thread.current)
233
- thread[:__threadlocal_array__]
234
- end
235
-
236
- def set_threadlocal_array(array, thread = Thread.current)
237
- thread[:__threadlocal_array__] = array
238
- end
239
- end
240
-
241
- # This exists only for use in testing
242
- # @!visibility private
243
- def value_for(thread)
244
- if array = get_threadlocal_array(thread)
245
- value = array[@index]
246
- if value.nil?
247
- @default
248
- elsif value.equal?(NIL_SENTINEL)
249
- nil
250
- else
251
- value
252
- end
253
- else
254
- @default
255
- end
256
- end
257
- end
258
-
259
- if Concurrent.on_jruby?
260
-
261
- # @!visibility private
262
- # @!macro internal_implementation_note
263
- class JavaThreadLocalVar < AbstractThreadLocalVar
264
-
265
- # @!macro thread_local_var_method_get
266
- def value
267
- value = @var.get
268
-
269
- if value.nil?
270
- @default
271
- elsif value == NIL_SENTINEL
272
- nil
273
- else
274
- value
275
- end
276
- end
277
-
278
- # @!macro thread_local_var_method_set
279
- def value=(value)
280
- @var.set(value)
281
- end
282
-
283
- # @!macro thread_local_var_method_bind
284
- def bind(value, &block)
285
- if block_given?
286
- old_value = @var.get
287
- begin
288
- @var.set(value)
289
- yield
290
- ensure
291
- @var.set(old_value)
292
- end
293
- end
294
- end
295
-
296
- protected
297
-
298
- # @!visibility private
299
- def allocate_storage
300
- @var = java.lang.ThreadLocal.new
301
- end
302
- end
303
- end
304
-
305
- # @!visibility private
306
- # @!macro internal_implementation_note
307
- ThreadLocalVarImplementation = case
308
- when Concurrent.on_jruby?
309
- JavaThreadLocalVar
310
- else
311
- RubyThreadLocalVar
312
- end
313
- private_constant :ThreadLocalVarImplementation
314
-
315
- # @!macro thread_local_var
99
+ # @!macro thread_local_var_public_api
316
100
  class ThreadLocalVar < ThreadLocalVarImplementation
317
-
318
- # @!method initialize(default = nil)
319
- # @!macro thread_local_var_method_initialize
320
-
321
- # @!method value
322
- # @!macro thread_local_var_method_get
323
-
324
- # @!method value=(value)
325
- # @!macro thread_local_var_method_set
326
-
327
- # @!method bind(value, &block)
328
- # @!macro thread_local_var_method_bind
329
-
330
101
  end
331
102
  end
@@ -0,0 +1 @@
1
+ require 'concurrent/atomic_reference/rbx'
@@ -1,4 +1,4 @@
1
- require 'concurrent/utility/native_extension_loader'
1
+ require 'concurrent/synchronization'
2
2
 
3
3
  if defined?(Concurrent::JavaAtomicReference)
4
4
  require 'concurrent/atomic_reference/direct_update'
@@ -1,4 +1,4 @@
1
- require 'thread'
1
+ require 'concurrent/synchronization'
2
2
  require 'concurrent/atomic_reference/direct_update'
3
3
  require 'concurrent/atomic_reference/numeric_cas_wrapper'
4
4
 
@@ -8,31 +8,31 @@ module Concurrent
8
8
  #
9
9
  # @!visibility private
10
10
  # @!macro internal_implementation_note
11
- class MutexAtomicReference
11
+ class MutexAtomicReference < Synchronization::LockableObject
12
12
  include Concurrent::AtomicDirectUpdate
13
13
  include Concurrent::AtomicNumericCompareAndSetWrapper
14
14
 
15
15
  # @!macro atomic_reference_method_initialize
16
16
  def initialize(value = nil)
17
- @mutex = Mutex.new
18
- @value = value
17
+ super()
18
+ synchronize { ns_initialize(value) }
19
19
  end
20
20
 
21
21
  # @!macro atomic_reference_method_get
22
22
  def get
23
- @mutex.synchronize { @value }
23
+ synchronize { @value }
24
24
  end
25
25
  alias_method :value, :get
26
26
 
27
27
  # @!macro atomic_reference_method_set
28
28
  def set(new_value)
29
- @mutex.synchronize { @value = new_value }
29
+ synchronize { @value = new_value }
30
30
  end
31
31
  alias_method :value=, :set
32
32
 
33
33
  # @!macro atomic_reference_method_get_and_set
34
34
  def get_and_set(new_value)
35
- @mutex.synchronize do
35
+ synchronize do
36
36
  old_value = @value
37
37
  @value = new_value
38
38
  old_value
@@ -42,7 +42,7 @@ module Concurrent
42
42
 
43
43
  # @!macro atomic_reference_method_compare_and_set
44
44
  def _compare_and_set(old_value, new_value)
45
- @mutex.synchronize do
45
+ synchronize do
46
46
  if @value.equal? old_value
47
47
  @value = new_value
48
48
  true
@@ -51,5 +51,11 @@ module Concurrent
51
51
  end
52
52
  end
53
53
  end
54
+
55
+ protected
56
+
57
+ def ns_initialize(value)
58
+ @value = value
59
+ end
54
60
  end
55
61
  end
@@ -1,5 +1,5 @@
1
1
  if defined? Concurrent::CAtomicReference
2
- require 'concurrent/utility/native_extension_loader'
2
+ require 'concurrent/synchronization'
3
3
  require 'concurrent/atomic_reference/direct_update'
4
4
  require 'concurrent/atomic_reference/numeric_cas_wrapper'
5
5