concurrent-ruby 1.0.5 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +115 -0
  3. data/Gemfile +42 -0
  4. data/{LICENSE.txt → LICENSE.md} +2 -0
  5. data/README.md +242 -105
  6. data/Rakefile +332 -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 +307 -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/concurrent-ruby.rb +1 -0
  23. data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +24 -20
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +7 -7
  25. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +18 -4
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +10 -10
  28. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
  29. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +26 -22
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +27 -23
  31. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  32. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +204 -0
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +7 -7
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +1 -1
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +9 -6
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +2 -0
  39. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -0
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +0 -0
  42. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
  43. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +3 -1
  44. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +43 -33
  45. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +8 -8
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +8 -8
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +3 -8
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +1 -1
  49. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
  51. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  53. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +3 -3
  55. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +0 -0
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +1 -2
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +30 -30
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +0 -0
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +3 -3
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +6 -1
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +7 -7
  65. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +15 -15
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +1 -1
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +2 -1
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +9 -7
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +21 -25
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +19 -25
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +5 -5
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +17 -17
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +27 -30
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  77. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +19 -16
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  80. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +12 -8
  81. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +0 -2
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +9 -4
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +0 -0
  85. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  86. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
  87. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  88. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
  89. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +3 -2
  90. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +6 -6
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +14 -17
  92. data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +4 -1
  94. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +8 -0
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +5 -6
  97. data/lib/concurrent-ruby/concurrent/map.rb +337 -0
  98. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +25 -14
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +2 -2
  101. data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  102. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +53 -21
  103. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  104. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  105. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +0 -0
  106. data/lib/concurrent-ruby/concurrent/set.rb +66 -0
  107. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +11 -0
  108. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +4 -5
  109. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -5
  110. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
  111. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +18 -4
  112. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  113. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
  114. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
  115. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  116. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +6 -6
  117. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
  118. data/lib/{concurrent/synchronization/mri_lockable_object.rb → concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb} +19 -14
  119. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +53 -23
  120. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +0 -0
  121. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
  122. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  123. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +11 -9
  124. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
  125. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  126. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  127. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
  128. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +63 -0
  129. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  130. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +9 -4
  131. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  132. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  133. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +5 -2
  134. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -1
  135. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +2 -2
  136. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +4 -4
  137. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/monotonic_time.rb +3 -3
  138. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  139. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
  140. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -2
  141. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  142. metadata +146 -131
  143. data/lib/concurrent/array.rb +0 -39
  144. data/lib/concurrent/atomic/atomic_reference.rb +0 -51
  145. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  146. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  147. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  148. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  149. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  150. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  151. data/lib/concurrent/atomics.rb +0 -53
  152. data/lib/concurrent/edge.rb +0 -26
  153. data/lib/concurrent/hash.rb +0 -36
  154. data/lib/concurrent/lazy_register.rb +0 -81
  155. data/lib/concurrent/map.rb +0 -240
  156. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  157. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  158. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
  159. data/lib/concurrent/utility/at_exit.rb +0 -97
  160. data/lib/concurrent/utility/native_extension_loader.rb +0 -73
  161. data/lib/concurrent/version.rb +0 -4
@@ -1,51 +0,0 @@
1
- require 'concurrent/synchronization'
2
- require 'concurrent/utility/engine'
3
- require 'concurrent/atomic_reference/concurrent_update_error'
4
- require 'concurrent/atomic_reference/mutex_atomic'
5
-
6
- begin
7
- # force fallback impl with FORCE_ATOMIC_FALLBACK=1
8
- if /[^0fF]/ =~ ENV['FORCE_ATOMIC_FALLBACK']
9
- ruby_engine = 'mutex_atomic'
10
- else
11
- ruby_engine = Concurrent.ruby_engine
12
- end
13
-
14
- require "concurrent/atomic_reference/#{ruby_engine}"
15
- rescue LoadError
16
- #warn 'Compiled extensions not installed, pure Ruby Atomic will be used.'
17
- end
18
-
19
- if defined? Concurrent::JavaAtomicReference
20
-
21
- # @!macro atomic_reference
22
- class Concurrent::AtomicReference < Concurrent::JavaAtomicReference
23
- end
24
-
25
- elsif defined? Concurrent::RbxAtomicReference
26
-
27
- # @!macro atomic_reference
28
- class Concurrent::AtomicReference < Concurrent::RbxAtomicReference
29
- end
30
-
31
- elsif defined? Concurrent::CAtomicReference
32
-
33
- # @!macro atomic_reference
34
- class Concurrent::AtomicReference < Concurrent::CAtomicReference
35
- end
36
-
37
- else
38
-
39
- # @!macro atomic_reference
40
- class Concurrent::AtomicReference < Concurrent::MutexAtomicReference
41
- end
42
- end
43
-
44
- class Concurrent::AtomicReference
45
- # @return [String] Short string representation.
46
- def to_s
47
- format '<#%s:0x%x value:%s>', self.class, object_id << 1, get
48
- end
49
-
50
- alias_method :inspect, :to_s
51
- end
@@ -1,8 +0,0 @@
1
- module Concurrent
2
-
3
- # @!macro atomic_reference
4
- class ConcurrentUpdateError < ThreadError
5
- # frozen pre-allocated backtrace to speed ConcurrentUpdateError
6
- CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
7
- end
8
- end
@@ -1,81 +0,0 @@
1
- require 'concurrent/atomic_reference/concurrent_update_error'
2
-
3
- module Concurrent
4
-
5
- # Define update methods that use direct paths
6
- #
7
- # @!visibility private
8
- # @!macro internal_implementation_note
9
- module AtomicDirectUpdate
10
-
11
- # @!macro [attach] atomic_reference_method_update
12
- #
13
- # Pass the current value to the given block, replacing it
14
- # with the block's result. May retry if the value changes
15
- # during the block's execution.
16
- #
17
- # @yield [Object] Calculate a new value for the atomic reference using
18
- # given (old) value
19
- # @yieldparam [Object] old_value the starting value of the atomic reference
20
- #
21
- # @return [Object] the new value
22
- def update
23
- true until compare_and_set(old_value = get, new_value = yield(old_value))
24
- new_value
25
- end
26
-
27
- # @!macro [attach] atomic_reference_method_try_update
28
- #
29
- # Pass the current value to the given block, replacing it
30
- # with the block's result. Return nil if the update fails.
31
- #
32
- # @yield [Object] Calculate a new value for the atomic reference using
33
- # given (old) value
34
- # @yieldparam [Object] old_value the starting value of the atomic reference
35
- #
36
- # @note This method was altered to avoid raising an exception by default.
37
- # Instead, this method now returns `nil` in case of failure. For more info,
38
- # please see: https://github.com/ruby-concurrency/concurrent-ruby/pull/336
39
- #
40
- # @return [Object] the new value, or nil if update failed
41
- def try_update
42
- old_value = get
43
- new_value = yield old_value
44
-
45
- return unless compare_and_set old_value, new_value
46
-
47
- new_value
48
- end
49
-
50
- # @!macro [attach] atomic_reference_method_try_update!
51
- #
52
- # Pass the current value to the given block, replacing it
53
- # with the block's result. Raise an exception if the update
54
- # fails.
55
- #
56
- # @yield [Object] Calculate a new value for the atomic reference using
57
- # given (old) value
58
- # @yieldparam [Object] old_value the starting value of the atomic reference
59
- #
60
- # @note This behavior mimics the behavior of the original
61
- # `AtomicReference#try_update` API. The reason this was changed was to
62
- # avoid raising exceptions (which are inherently slow) by default. For more
63
- # info: https://github.com/ruby-concurrency/concurrent-ruby/pull/336
64
- #
65
- # @return [Object] the new value
66
- #
67
- # @raise [Concurrent::ConcurrentUpdateError] if the update fails
68
- def try_update!
69
- old_value = get
70
- new_value = yield old_value
71
- unless compare_and_set(old_value, new_value)
72
- if $VERBOSE
73
- raise ConcurrentUpdateError, "Update failed"
74
- else
75
- raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE
76
- end
77
- end
78
- new_value
79
- end
80
- end
81
- end
@@ -1,2 +0,0 @@
1
- require 'atomic'
2
- require 'concurrent/atomic_reference/rbx'
@@ -1,16 +0,0 @@
1
- require 'concurrent/synchronization'
2
-
3
- if defined?(Concurrent::JavaAtomicReference)
4
- require 'concurrent/atomic_reference/direct_update'
5
-
6
- module Concurrent
7
-
8
- # @!macro atomic_reference
9
- #
10
- # @!visibility private
11
- # @!macro internal_implementation_note
12
- class JavaAtomicReference
13
- include Concurrent::AtomicDirectUpdate
14
- end
15
- end
16
- end
@@ -1,22 +0,0 @@
1
- require 'concurrent/atomic_reference/direct_update'
2
- require 'concurrent/atomic_reference/numeric_cas_wrapper'
3
-
4
- module Concurrent
5
-
6
- # @!macro atomic_reference
7
- #
8
- # @note Extends `Rubinius::AtomicReference` version adding aliases
9
- # and numeric logic.
10
- #
11
- # @!visibility private
12
- # @!macro internal_implementation_note
13
- class RbxAtomicReference < Rubinius::AtomicReference
14
- alias _compare_and_set compare_and_set
15
- include Concurrent::AtomicDirectUpdate
16
- include Concurrent::AtomicNumericCompareAndSetWrapper
17
-
18
- alias_method :value, :get
19
- alias_method :value=, :set
20
- alias_method :swap, :get_and_set
21
- end
22
- end
@@ -1,32 +0,0 @@
1
- if defined? Concurrent::CAtomicReference
2
- require 'concurrent/synchronization'
3
- require 'concurrent/atomic_reference/direct_update'
4
- require 'concurrent/atomic_reference/numeric_cas_wrapper'
5
-
6
- module Concurrent
7
-
8
- # @!macro atomic_reference
9
- #
10
- # @!visibility private
11
- # @!macro internal_implementation_note
12
- class CAtomicReference
13
- include Concurrent::AtomicDirectUpdate
14
- include Concurrent::AtomicNumericCompareAndSetWrapper
15
-
16
- # @!method initialize
17
- # @!macro atomic_reference_method_initialize
18
-
19
- # @!method get
20
- # @!macro atomic_reference_method_get
21
-
22
- # @!method set
23
- # @!macro atomic_reference_method_set
24
-
25
- # @!method get_and_set
26
- # @!macro atomic_reference_method_get_and_set
27
-
28
- # @!method _compare_and_set
29
- # @!macro atomic_reference_method_compare_and_set
30
- end
31
- end
32
- end
@@ -1,53 +0,0 @@
1
- # @!macro [new] atomic_reference
2
- #
3
- # An object reference that may be updated atomically. All read and write
4
- # operations have java volatile semantic.
5
- #
6
- # @!macro thread_safe_variable_comparison
7
- #
8
- # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
9
- # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html
10
- #
11
- # @!method initialize
12
- # @!macro [new] atomic_reference_method_initialize
13
- # @param [Object] value The initial value.
14
- #
15
- # @!method get
16
- # @!macro [new] atomic_reference_method_get
17
- # Gets the current value.
18
- # @return [Object] the current value
19
- #
20
- # @!method set
21
- # @!macro [new] atomic_reference_method_set
22
- # Sets to the given value.
23
- # @param [Object] new_value the new value
24
- # @return [Object] the new value
25
- #
26
- # @!method get_and_set
27
- # @!macro [new] atomic_reference_method_get_and_set
28
- # Atomically sets to the given value and returns the old value.
29
- # @param [Object] new_value the new value
30
- # @return [Object] the old value
31
- #
32
- # @!method compare_and_set
33
- # @!macro [new] atomic_reference_method_compare_and_set
34
- #
35
- # Atomically sets the value to the given updated value if
36
- # the current value == the expected value.
37
- #
38
- # @param [Object] old_value the expected value
39
- # @param [Object] new_value the new value
40
- #
41
- # @return [Boolean] `true` if successful. A `false` return indicates
42
- # that the actual value was not equal to the expected value.
43
-
44
- require 'concurrent/atomic/atomic_reference'
45
- require 'concurrent/atomic/atomic_boolean'
46
- require 'concurrent/atomic/atomic_fixnum'
47
- require 'concurrent/atomic/cyclic_barrier'
48
- require 'concurrent/atomic/count_down_latch'
49
- require 'concurrent/atomic/event'
50
- require 'concurrent/atomic/read_write_lock'
51
- require 'concurrent/atomic/reentrant_read_write_lock'
52
- require 'concurrent/atomic/semaphore'
53
- require 'concurrent/atomic/thread_local_var'
@@ -1,26 +0,0 @@
1
- module Concurrent
2
-
3
- # A submodule for unstable, highly experimental features that are likely to
4
- # change often and which may never become part of the core gem. Also for
5
- # new, experimental version of abstractions already in the core gem.
6
- #
7
- # Most new features should start in this module, clearly indicating the
8
- # experimental and unstable nature of the feature. Once a feature becomes
9
- # more stable and is a candidate for inclusion in the core gem it should
10
- # be moved up to the `Concurrent` module, where it would reside once merged
11
- # into the core gem.
12
- #
13
- # The only exception to this is for features which *replace* features from
14
- # the core gem in ways that are breaking and not backward compatible. These
15
- # features should remain in this module until merged into the core gem. This
16
- # will prevent namespace collisions.
17
- #
18
- # @!macro [attach] edge_warning
19
- # @api Edge
20
- # @note **Edge Feature:** Edge features are under active development and may change frequently. They are expected not to
21
- # keep backward compatibility (there may also lack tests and documentation). Semantic versions will
22
- # be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move
23
- # to `concurrent-ruby` when final.
24
- module Edge
25
- end
26
- end
@@ -1,36 +0,0 @@
1
- require 'concurrent/utility/engine'
2
- require 'concurrent/thread_safe/util'
3
-
4
- module Concurrent
5
- if Concurrent.on_cruby?
6
-
7
- # @!macro [attach] concurrent_hash
8
- #
9
- # A thread-safe subclass of Hash. This version locks against the object
10
- # itself for every method call, ensuring only one thread can be reading
11
- # or writing at a time. This includes iteration methods like `#each`,
12
- # which takes the lock repeatedly when reading an item.
13
- #
14
- # @see http://ruby-doc.org/core-2.2.0/Hash.html Ruby standard library `Hash`
15
- class Hash < ::Hash;
16
- end
17
-
18
- elsif Concurrent.on_jruby?
19
- require 'jruby/synchronized'
20
-
21
- # @!macro concurrent_hash
22
- class Hash < ::Hash
23
- include JRuby::Synchronized
24
- end
25
-
26
- elsif Concurrent.on_rbx? || Concurrent.on_truffle?
27
- require 'monitor'
28
- require 'concurrent/thread_safe/util/array_hash_rbx'
29
-
30
- # @!macro concurrent_hash
31
- class Hash < ::Hash
32
- end
33
-
34
- ThreadSafe::Util.make_synchronized_on_rbx Hash
35
- end
36
- end
@@ -1,81 +0,0 @@
1
- require 'concurrent/atomic/atomic_reference'
2
- require 'concurrent/delay'
3
-
4
- module Concurrent
5
-
6
- # Hash-like collection that store lazys evaluated values.
7
- #
8
- # @example
9
- # register = Concurrent::LazyRegister.new
10
- # #=> #<Concurrent::LazyRegister:0x007fd7ecd5e230 @Data=#<Concurrent::AtomicReference:0x007fd7ecd5e1e0>>
11
- # register[:key]
12
- # #=> nil
13
- # register.add(:key) { Concurrent::Actor.spawn!(Actor::AdHoc, :ping) { -> message { message } } }
14
- # #=> #<Concurrent::LazyRegister:0x007fd7ecd5e230 @Data=#<Concurrent::AtomicReference:0x007fd7ecd5e1e0>>
15
- # register[:key]
16
- # #=> #<Concurrent::Actor::Reference /ping (Concurrent::Actor::AdHoc)>
17
- #
18
- # @!macro edge_warning
19
- class LazyRegister < Synchronization::Object
20
-
21
- private(*attr_atomic(:data))
22
-
23
- def initialize
24
- super
25
- self.data = {}
26
- end
27
-
28
- # Element reference. Retrieves the value object corresponding to the
29
- # key object. Returns nil if the key is not found. Raises an exception
30
- # if the stored item raised an exception when the block was evaluated.
31
- #
32
- # @param [Object] key
33
- # @return [Object] value stored for the key or nil if the key is not found
34
- #
35
- # @raise Exception when the initialization block fails
36
- def [](key)
37
- delay = data[key]
38
- delay ? delay.value! : nil
39
- end
40
-
41
- # Returns true if the given key is present.
42
- #
43
- # @param [Object] key
44
- # @return [true, false] if the key is registered
45
- def registered?(key)
46
- data.key?(key)
47
- end
48
-
49
- alias_method :key?, :registered?
50
- alias_method :has_key?, :registered?
51
-
52
- # Element assignment. Associates the value given by value with the
53
- # key given by key.
54
- #
55
- # @param [Object] key
56
- # @yield the object to store under the key
57
- #
58
- # @return [LazyRegister] self
59
- def register(key, &block)
60
- delay = Delay.new(executor: :immediate, &block)
61
- update_data { |h| h.merge(key => delay) }
62
- self
63
- end
64
-
65
- alias_method :add, :register
66
- alias_method :store, :register
67
-
68
- # Un-registers the object under key, realized or not.
69
- #
70
- # @param [Object] key
71
- #
72
- # @return [LazyRegister] self
73
- def unregister(key)
74
- update_data { |h| h.dup.tap { |j| j.delete(key) } }
75
- self
76
- end
77
-
78
- alias_method :remove, :unregister
79
- alias_method :delete, :unregister
80
- end
81
- end
@@ -1,240 +0,0 @@
1
- require 'thread'
2
- require 'concurrent/constants'
3
- require 'concurrent/synchronization'
4
-
5
- module Concurrent
6
- # @!visibility private
7
- module Collection
8
-
9
- # @!visibility private
10
- MapImplementation = if Concurrent.java_extensions_loaded?
11
- # noinspection RubyResolve
12
- JRubyMapBackend
13
- elsif defined?(RUBY_ENGINE)
14
- case RUBY_ENGINE
15
- when 'ruby'
16
- require 'concurrent/collection/map/mri_map_backend'
17
- MriMapBackend
18
- when 'rbx'
19
- require 'concurrent/collection/map/atomic_reference_map_backend'
20
- AtomicReferenceMapBackend
21
- when 'jruby+truffle'
22
- require 'concurrent/collection/map/atomic_reference_map_backend'
23
- AtomicReferenceMapBackend
24
- else
25
- warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' if $VERBOSE
26
- require 'concurrent/collection/map/synchronized_map_backend'
27
- SynchronizedMapBackend
28
- end
29
- else
30
- MriMapBackend
31
- end
32
- end
33
-
34
- # `Concurrent::Map` is a hash-like object and should have much better performance
35
- # characteristics, especially under high concurrency, than `Concurrent::Hash`.
36
- # However, `Concurrent::Map `is not strictly semantically equivalent to a ruby `Hash`
37
- # -- for instance, it does not necessarily retain ordering by insertion time as `Hash`
38
- # does. For most uses it should do fine though, and we recommend you consider
39
- # `Concurrent::Map` instead of `Concurrent::Hash` for your concurrency-safe hash needs.
40
- #
41
- # > require 'concurrent'
42
- # >
43
- # > map = Concurrent::Map.new
44
- class Map < Collection::MapImplementation
45
-
46
- # @!macro [new] map_method_is_atomic
47
- # This method is atomic. Atomic methods of `Map` which accept a block
48
- # do not allow the `self` instance to be used within the block. Doing
49
- # so will cause a deadlock.
50
-
51
- # @!method put_if_absent
52
- # @!macro map_method_is_atomic
53
-
54
- # @!method compute_if_absent
55
- # @!macro map_method_is_atomic
56
-
57
- # @!method compute_if_present
58
- # @!macro map_method_is_atomic
59
-
60
- # @!method compute
61
- # @!macro map_method_is_atomic
62
-
63
- # @!method merge_pair
64
- # @!macro map_method_is_atomic
65
-
66
- # @!method replace_pair
67
- # @!macro map_method_is_atomic
68
-
69
- # @!method replace_if_exists
70
- # @!macro map_method_is_atomic
71
-
72
- # @!method get_and_set
73
- # @!macro map_method_is_atomic
74
-
75
- # @!method delete
76
- # @!macro map_method_is_atomic
77
-
78
- # @!method delete_pair
79
- # @!macro map_method_is_atomic
80
-
81
- def initialize(options = nil, &block)
82
- if options.kind_of?(::Hash)
83
- validate_options_hash!(options)
84
- else
85
- options = nil
86
- end
87
-
88
- super(options)
89
- @default_proc = block
90
- end
91
-
92
- def [](key)
93
- if value = super # non-falsy value is an existing mapping, return it right away
94
- value
95
- # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call
96
- # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value
97
- # would be returned)
98
- # note: nil == value check is not technically necessary
99
- elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL))
100
- @default_proc.call(self, key)
101
- else
102
- value
103
- end
104
- end
105
-
106
- alias_method :get, :[]
107
- alias_method :put, :[]=
108
-
109
- # @!macro [attach] map_method_not_atomic
110
- # The "fetch-then-act" methods of `Map` are not atomic. `Map` is intended
111
- # to be use as a concurrency primitive with strong happens-before
112
- # guarantees. It is not intended to be used as a high-level abstraction
113
- # supporting complex operations. All read and write operations are
114
- # thread safe, but no guarantees are made regarding race conditions
115
- # between the fetch operation and yielding to the block. Additionally,
116
- # this method does not support recursion. This is due to internal
117
- # constraints that are very unlikely to change in the near future.
118
- def fetch(key, default_value = NULL)
119
- if NULL != (value = get_or_default(key, NULL))
120
- value
121
- elsif block_given?
122
- yield key
123
- elsif NULL != default_value
124
- default_value
125
- else
126
- raise_fetch_no_key
127
- end
128
- end
129
-
130
- # @!macro map_method_not_atomic
131
- def fetch_or_store(key, default_value = NULL)
132
- fetch(key) do
133
- put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value))
134
- end
135
- end
136
-
137
- # @!macro map_method_is_atomic
138
- def put_if_absent(key, value)
139
- computed = false
140
- result = compute_if_absent(key) do
141
- computed = true
142
- value
143
- end
144
- computed ? nil : result
145
- end unless method_defined?(:put_if_absent)
146
-
147
- def value?(value)
148
- each_value do |v|
149
- return true if value.equal?(v)
150
- end
151
- false
152
- end
153
-
154
- def keys
155
- arr = []
156
- each_pair {|k, v| arr << k}
157
- arr
158
- end unless method_defined?(:keys)
159
-
160
- def values
161
- arr = []
162
- each_pair {|k, v| arr << v}
163
- arr
164
- end unless method_defined?(:values)
165
-
166
- def each_key
167
- each_pair {|k, v| yield k}
168
- end unless method_defined?(:each_key)
169
-
170
- def each_value
171
- each_pair {|k, v| yield v}
172
- end unless method_defined?(:each_value)
173
-
174
- alias_method :each, :each_pair unless method_defined?(:each)
175
-
176
- def key(value)
177
- each_pair {|k, v| return k if v == value}
178
- nil
179
- end unless method_defined?(:key)
180
- alias_method :index, :key if RUBY_VERSION < '1.9'
181
-
182
- def empty?
183
- each_pair {|k, v| return false}
184
- true
185
- end unless method_defined?(:empty?)
186
-
187
- def size
188
- count = 0
189
- each_pair {|k, v| count += 1}
190
- count
191
- end unless method_defined?(:size)
192
-
193
- def marshal_dump
194
- raise TypeError, "can't dump hash with default proc" if @default_proc
195
- h = {}
196
- each_pair {|k, v| h[k] = v}
197
- h
198
- end
199
-
200
- def marshal_load(hash)
201
- initialize
202
- populate_from(hash)
203
- end
204
-
205
- undef :freeze
206
-
207
- # @!visibility private
208
- DEFAULT_OBJ_ID_STR_WIDTH = 0.size == 4 ? 7 : 14 # we want to look "native", 7 for 32-bit, 14 for 64-bit
209
- # override default #inspect() method: firstly, we don't want to be spilling our guts (i-vars), secondly, MRI backend's
210
- # #inspect() call on its @backend i-var will bump @backend's iter level while possibly yielding GVL
211
- def inspect
212
- id_str = (object_id << 1).to_s(16).rjust(DEFAULT_OBJ_ID_STR_WIDTH, '0')
213
- "#<#{self.class.name}:0x#{id_str} entries=#{size} default_proc=#{@default_proc.inspect}>"
214
- end
215
-
216
- private
217
- def raise_fetch_no_key
218
- raise KeyError, 'key not found'
219
- end
220
-
221
- def initialize_copy(other)
222
- super
223
- populate_from(other)
224
- end
225
-
226
- def populate_from(hash)
227
- hash.each_pair {|k, v| self[k] = v}
228
- self
229
- end
230
-
231
- def validate_options_hash!(options)
232
- if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Integer) || initial_capacity < 0)
233
- raise ArgumentError, ":initial_capacity must be a positive Integer"
234
- end
235
- if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1)
236
- raise ArgumentError, ":load_factor must be a number between 0 and 1"
237
- end
238
- end
239
- end
240
- end