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
@@ -3,7 +3,7 @@ require 'concurrent/collection/copy_on_notify_observer_set'
3
3
  require 'concurrent/concern/observable'
4
4
  require 'concurrent/synchronization'
5
5
 
6
- # @!macro [new] thread_safe_variable_comparison
6
+ # @!macro thread_safe_variable_comparison
7
7
  #
8
8
  # ## Thread-safe Variable Classes
9
9
  #
@@ -18,7 +18,7 @@ require 'concurrent/synchronization'
18
18
  # uncoordinated, *synchronous* change of individual values. Best used when
19
19
  # the value will undergo frequent reads but only occasional, though complex,
20
20
  # updates. Suitable when the result of an update must be known immediately.
21
- # * *{Concurrent::AtomicReference}:* A simple object reference that can be
21
+ # * *{Concurrent::AtomicReference}:* A simple object reference that can be updated
22
22
  # atomically. Updates are synchronous but fast. Best used when updates a
23
23
  # simple set operations. Not suitable when updates are complex.
24
24
  # {Concurrent::AtomicBoolean} and {Concurrent::AtomicFixnum} are similar
@@ -96,8 +96,15 @@ module Concurrent
96
96
  include Concern::Observable
97
97
 
98
98
  safe_initialization!
99
- private(*attr_atomic(:value))
99
+ attr_atomic(:value)
100
+ private :value=, :swap_value, :compare_and_set_value, :update_value
100
101
  public :value
102
+ alias_method :deref, :value
103
+
104
+ # @!method value
105
+ # The current value of the atom.
106
+ #
107
+ # @return [Object] The current value.
101
108
 
102
109
  # Create a new atom with the given initial value.
103
110
  #
@@ -118,13 +125,6 @@ module Concurrent
118
125
  self.value = value
119
126
  end
120
127
 
121
- # @!method value
122
- # The current value of the atom.
123
- #
124
- # @return [Object] The current value.
125
-
126
- alias_method :deref, :value
127
-
128
128
  # Atomically swaps the value of atom using the given block. The current
129
129
  # value will be passed to the block, as will any arguments passed as
130
130
  # arguments to the function. The new value will be validated against the
@@ -5,19 +5,19 @@ module Concurrent
5
5
 
6
6
  ###################################################################
7
7
 
8
- # @!macro [new] atomic_boolean_method_initialize
8
+ # @!macro atomic_boolean_method_initialize
9
9
  #
10
10
  # Creates a new `AtomicBoolean` with the given initial value.
11
11
  #
12
12
  # @param [Boolean] initial the initial value
13
13
 
14
- # @!macro [new] atomic_boolean_method_value_get
14
+ # @!macro atomic_boolean_method_value_get
15
15
  #
16
16
  # Retrieves the current `Boolean` value.
17
17
  #
18
18
  # @return [Boolean] the current value
19
19
 
20
- # @!macro [new] atomic_boolean_method_value_set
20
+ # @!macro atomic_boolean_method_value_set
21
21
  #
22
22
  # Explicitly sets the value.
23
23
  #
@@ -25,33 +25,33 @@ module Concurrent
25
25
  #
26
26
  # @return [Boolean] the current value
27
27
 
28
- # @!macro [new] atomic_boolean_method_true_question
28
+ # @!macro atomic_boolean_method_true_question
29
29
  #
30
30
  # Is the current value `true`
31
31
  #
32
32
  # @return [Boolean] true if the current value is `true`, else false
33
33
 
34
- # @!macro [new] atomic_boolean_method_false_question
34
+ # @!macro atomic_boolean_method_false_question
35
35
  #
36
36
  # Is the current value `false`
37
37
  #
38
38
  # @return [Boolean] true if the current value is `false`, else false
39
39
 
40
- # @!macro [new] atomic_boolean_method_make_true
40
+ # @!macro atomic_boolean_method_make_true
41
41
  #
42
42
  # Explicitly sets the value to true.
43
43
  #
44
- # @return [Boolean] true is value has changed, otherwise false
44
+ # @return [Boolean] true if value has changed, otherwise false
45
45
 
46
- # @!macro [new] atomic_boolean_method_make_false
46
+ # @!macro atomic_boolean_method_make_false
47
47
  #
48
48
  # Explicitly sets the value to false.
49
49
  #
50
- # @return [Boolean] true is value has changed, otherwise false
50
+ # @return [Boolean] true if value has changed, otherwise false
51
51
 
52
52
  ###################################################################
53
53
 
54
- # @!macro [new] atomic_boolean_public_api
54
+ # @!macro atomic_boolean_public_api
55
55
  #
56
56
  # @!method initialize(initial = false)
57
57
  # @!macro atomic_boolean_method_initialize
@@ -88,7 +88,7 @@ module Concurrent
88
88
  end
89
89
  private_constant :AtomicBooleanImplementation
90
90
 
91
- # @!macro [attach] atomic_boolean
91
+ # @!macro atomic_boolean
92
92
  #
93
93
  # A boolean value that can be updated atomically. Reads and writes to an atomic
94
94
  # boolean and thread-safe and guaranteed to succeed. Reads and writes may block
@@ -96,17 +96,21 @@ module Concurrent
96
96
  #
97
97
  # @!macro thread_safe_variable_comparison
98
98
  #
99
- # Testing with ruby 2.1.2
100
- # Testing with Concurrent::MutexAtomicBoolean...
101
- # 2.790000 0.000000 2.790000 ( 2.791454)
102
- # Testing with Concurrent::CAtomicBoolean...
103
- # 0.740000 0.000000 0.740000 ( 0.740206)
99
+ # Performance:
100
+ #
101
+ # ```
102
+ # Testing with ruby 2.1.2
103
+ # Testing with Concurrent::MutexAtomicBoolean...
104
+ # 2.790000 0.000000 2.790000 ( 2.791454)
105
+ # Testing with Concurrent::CAtomicBoolean...
106
+ # 0.740000 0.000000 0.740000 ( 0.740206)
104
107
  #
105
- # Testing with jruby 1.9.3
106
- # Testing with Concurrent::MutexAtomicBoolean...
107
- # 5.240000 2.520000 7.760000 ( 3.683000)
108
- # Testing with Concurrent::JavaAtomicBoolean...
109
- # 3.340000 0.010000 3.350000 ( 0.855000)
108
+ # Testing with jruby 1.9.3
109
+ # Testing with Concurrent::MutexAtomicBoolean...
110
+ # 5.240000 2.520000 7.760000 ( 3.683000)
111
+ # Testing with Concurrent::JavaAtomicBoolean...
112
+ # 3.340000 0.010000 3.350000 ( 0.855000)
113
+ # ```
110
114
  #
111
115
  # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean
112
116
  #
@@ -114,7 +118,7 @@ module Concurrent
114
118
  class AtomicBoolean < AtomicBooleanImplementation
115
119
  # @return [String] Short string representation.
116
120
  def to_s
117
- format '<#%s:0x%x value:%s>', self.class, object_id << 1, value
121
+ format '%s value:%s>', super[0..-2], value
118
122
  end
119
123
 
120
124
  alias_method :inspect, :to_s
@@ -5,20 +5,20 @@ module Concurrent
5
5
 
6
6
  ###################################################################
7
7
 
8
- # @!macro [new] atomic_fixnum_method_initialize
8
+ # @!macro atomic_fixnum_method_initialize
9
9
  #
10
10
  # Creates a new `AtomicFixnum` with the given initial value.
11
11
  #
12
12
  # @param [Fixnum] initial the initial value
13
13
  # @raise [ArgumentError] if the initial value is not a `Fixnum`
14
14
 
15
- # @!macro [new] atomic_fixnum_method_value_get
15
+ # @!macro atomic_fixnum_method_value_get
16
16
  #
17
17
  # Retrieves the current `Fixnum` value.
18
18
  #
19
19
  # @return [Fixnum] the current value
20
20
 
21
- # @!macro [new] atomic_fixnum_method_value_set
21
+ # @!macro atomic_fixnum_method_value_set
22
22
  #
23
23
  # Explicitly sets the value.
24
24
  #
@@ -28,7 +28,7 @@ module Concurrent
28
28
  #
29
29
  # @raise [ArgumentError] if the new value is not a `Fixnum`
30
30
 
31
- # @!macro [new] atomic_fixnum_method_increment
31
+ # @!macro atomic_fixnum_method_increment
32
32
  #
33
33
  # Increases the current value by the given amount (defaults to 1).
34
34
  #
@@ -36,7 +36,7 @@ module Concurrent
36
36
  #
37
37
  # @return [Fixnum] the current value after incrementation
38
38
 
39
- # @!macro [new] atomic_fixnum_method_decrement
39
+ # @!macro atomic_fixnum_method_decrement
40
40
  #
41
41
  # Decreases the current value by the given amount (defaults to 1).
42
42
  #
@@ -44,7 +44,7 @@ module Concurrent
44
44
  #
45
45
  # @return [Fixnum] the current value after decrementation
46
46
 
47
- # @!macro [new] atomic_fixnum_method_compare_and_set
47
+ # @!macro atomic_fixnum_method_compare_and_set
48
48
  #
49
49
  # Atomically sets the value to the given updated value if the current
50
50
  # value == the expected value.
@@ -52,9 +52,9 @@ module Concurrent
52
52
  # @param [Fixnum] expect the expected value
53
53
  # @param [Fixnum] update the new value
54
54
  #
55
- # @return [Fixnum] true if the value was updated else false
55
+ # @return [Boolean] true if the value was updated else false
56
56
 
57
- # @!macro [new] atomic_fixnum_method_update
57
+ # @!macro atomic_fixnum_method_update
58
58
  #
59
59
  # Pass the current value to the given block, replacing it
60
60
  # with the block's result. May retry if the value changes
@@ -68,7 +68,7 @@ module Concurrent
68
68
 
69
69
  ###################################################################
70
70
 
71
- # @!macro [new] atomic_fixnum_public_api
71
+ # @!macro atomic_fixnum_public_api
72
72
  #
73
73
  # @!method initialize(initial = 0)
74
74
  # @!macro atomic_fixnum_method_initialize
@@ -79,10 +79,10 @@ module Concurrent
79
79
  # @!method value=(value)
80
80
  # @!macro atomic_fixnum_method_value_set
81
81
  #
82
- # @!method increment
82
+ # @!method increment(delta = 1)
83
83
  # @!macro atomic_fixnum_method_increment
84
84
  #
85
- # @!method decrement
85
+ # @!method decrement(delta = 1)
86
86
  # @!macro atomic_fixnum_method_decrement
87
87
  #
88
88
  # @!method compare_and_set(expect, update)
@@ -105,7 +105,7 @@ module Concurrent
105
105
  end
106
106
  private_constant :AtomicFixnumImplementation
107
107
 
108
- # @!macro [attach] atomic_fixnum
108
+ # @!macro atomic_fixnum
109
109
  #
110
110
  # A numeric value that can be updated atomically. Reads and writes to an atomic
111
111
  # fixnum and thread-safe and guaranteed to succeed. Reads and writes may block
@@ -113,17 +113,21 @@ module Concurrent
113
113
  #
114
114
  # @!macro thread_safe_variable_comparison
115
115
  #
116
- # Testing with ruby 2.1.2
117
- # Testing with Concurrent::MutexAtomicFixnum...
118
- # 3.130000 0.000000 3.130000 ( 3.136505)
119
- # Testing with Concurrent::CAtomicFixnum...
120
- # 0.790000 0.000000 0.790000 ( 0.785550)
116
+ # Performance:
117
+ #
118
+ # ```
119
+ # Testing with ruby 2.1.2
120
+ # Testing with Concurrent::MutexAtomicFixnum...
121
+ # 3.130000 0.000000 3.130000 ( 3.136505)
122
+ # Testing with Concurrent::CAtomicFixnum...
123
+ # 0.790000 0.000000 0.790000 ( 0.785550)
121
124
  #
122
- # Testing with jruby 1.9.3
123
- # Testing with Concurrent::MutexAtomicFixnum...
124
- # 5.460000 2.460000 7.920000 ( 3.715000)
125
- # Testing with Concurrent::JavaAtomicFixnum...
126
- # 4.520000 0.030000 4.550000 ( 1.187000)
125
+ # Testing with jruby 1.9.3
126
+ # Testing with Concurrent::MutexAtomicFixnum...
127
+ # 5.460000 2.460000 7.920000 ( 3.715000)
128
+ # Testing with Concurrent::JavaAtomicFixnum...
129
+ # 4.520000 0.030000 4.550000 ( 1.187000)
130
+ # ```
127
131
  #
128
132
  # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong
129
133
  #
@@ -131,7 +135,7 @@ module Concurrent
131
135
  class AtomicFixnum < AtomicFixnumImplementation
132
136
  # @return [String] Short string representation.
133
137
  def to_s
134
- format '<#%s:0x%x value:%s>', self.class, object_id << 1, value
138
+ format '%s value:%s>', super[0..-2], value
135
139
  end
136
140
 
137
141
  alias_method :inspect, :to_s
@@ -0,0 +1,164 @@
1
+ module Concurrent
2
+ # An atomic reference which maintains an object reference along with a mark bit
3
+ # that can be updated atomically.
4
+ #
5
+ # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicMarkableReference.html
6
+ # java.util.concurrent.atomic.AtomicMarkableReference
7
+ class AtomicMarkableReference < ::Concurrent::Synchronization::Object
8
+
9
+ attr_atomic(:reference)
10
+ private :reference, :reference=, :swap_reference, :compare_and_set_reference, :update_reference
11
+
12
+ def initialize(value = nil, mark = false)
13
+ super()
14
+ self.reference = immutable_array(value, mark)
15
+ end
16
+
17
+ # Atomically sets the value and mark to the given updated value and
18
+ # mark given both:
19
+ # - the current value == the expected value &&
20
+ # - the current mark == the expected mark
21
+ #
22
+ # @param [Object] expected_val the expected value
23
+ # @param [Object] new_val the new value
24
+ # @param [Boolean] expected_mark the expected mark
25
+ # @param [Boolean] new_mark the new mark
26
+ #
27
+ # @return [Boolean] `true` if successful. A `false` return indicates
28
+ # that the actual value was not equal to the expected value or the
29
+ # actual mark was not equal to the expected mark
30
+ def compare_and_set(expected_val, new_val, expected_mark, new_mark)
31
+ # Memoize a valid reference to the current AtomicReference for
32
+ # later comparison.
33
+ current = reference
34
+ curr_val, curr_mark = current
35
+
36
+ # Ensure that that the expected marks match.
37
+ return false unless expected_mark == curr_mark
38
+
39
+ if expected_val.is_a? Numeric
40
+ # If the object is a numeric, we need to ensure we are comparing
41
+ # the numerical values
42
+ return false unless expected_val == curr_val
43
+ else
44
+ # Otherwise, we need to ensure we are comparing the object identity.
45
+ # Theoretically, this could be incorrect if a user monkey-patched
46
+ # `Object#equal?`, but they should know that they are playing with
47
+ # fire at that point.
48
+ return false unless expected_val.equal? curr_val
49
+ end
50
+
51
+ prospect = immutable_array(new_val, new_mark)
52
+
53
+ compare_and_set_reference current, prospect
54
+ end
55
+
56
+ alias_method :compare_and_swap, :compare_and_set
57
+
58
+ # Gets the current reference and marked values.
59
+ #
60
+ # @return [Array] the current reference and marked values
61
+ def get
62
+ reference
63
+ end
64
+
65
+ # Gets the current value of the reference
66
+ #
67
+ # @return [Object] the current value of the reference
68
+ def value
69
+ reference[0]
70
+ end
71
+
72
+ # Gets the current marked value
73
+ #
74
+ # @return [Boolean] the current marked value
75
+ def mark
76
+ reference[1]
77
+ end
78
+
79
+ alias_method :marked?, :mark
80
+
81
+ # _Unconditionally_ sets to the given value of both the reference and
82
+ # the mark.
83
+ #
84
+ # @param [Object] new_val the new value
85
+ # @param [Boolean] new_mark the new mark
86
+ #
87
+ # @return [Array] both the new value and the new mark
88
+ def set(new_val, new_mark)
89
+ self.reference = immutable_array(new_val, new_mark)
90
+ end
91
+
92
+ # Pass the current value and marked state to the given block, replacing it
93
+ # with the block's results. May retry if the value changes during the
94
+ # block's execution.
95
+ #
96
+ # @yield [Object] Calculate a new value and marked state for the atomic
97
+ # reference using given (old) value and (old) marked
98
+ # @yieldparam [Object] old_val the starting value of the atomic reference
99
+ # @yieldparam [Boolean] old_mark the starting state of marked
100
+ #
101
+ # @return [Array] the new value and new mark
102
+ def update
103
+ loop do
104
+ old_val, old_mark = reference
105
+ new_val, new_mark = yield old_val, old_mark
106
+
107
+ if compare_and_set old_val, new_val, old_mark, new_mark
108
+ return immutable_array(new_val, new_mark)
109
+ end
110
+ end
111
+ end
112
+
113
+ # Pass the current value to the given block, replacing it
114
+ # with the block's result. Raise an exception if the update
115
+ # fails.
116
+ #
117
+ # @yield [Object] Calculate a new value and marked state for the atomic
118
+ # reference using given (old) value and (old) marked
119
+ # @yieldparam [Object] old_val the starting value of the atomic reference
120
+ # @yieldparam [Boolean] old_mark the starting state of marked
121
+ #
122
+ # @return [Array] the new value and marked state
123
+ #
124
+ # @raise [Concurrent::ConcurrentUpdateError] if the update fails
125
+ def try_update!
126
+ old_val, old_mark = reference
127
+ new_val, new_mark = yield old_val, old_mark
128
+
129
+ unless compare_and_set old_val, new_val, old_mark, new_mark
130
+ fail ::Concurrent::ConcurrentUpdateError,
131
+ 'AtomicMarkableReference: Update failed due to race condition.',
132
+ 'Note: If you would like to guarantee an update, please use ' +
133
+ 'the `AtomicMarkableReference#update` method.'
134
+ end
135
+
136
+ immutable_array(new_val, new_mark)
137
+ end
138
+
139
+ # Pass the current value to the given block, replacing it with the
140
+ # block's result. Simply return nil if update fails.
141
+ #
142
+ # @yield [Object] Calculate a new value and marked state for the atomic
143
+ # reference using given (old) value and (old) marked
144
+ # @yieldparam [Object] old_val the starting value of the atomic reference
145
+ # @yieldparam [Boolean] old_mark the starting state of marked
146
+ #
147
+ # @return [Array] the new value and marked state, or nil if
148
+ # the update failed
149
+ def try_update
150
+ old_val, old_mark = reference
151
+ new_val, new_mark = yield old_val, old_mark
152
+
153
+ return unless compare_and_set old_val, new_val, old_mark, new_mark
154
+
155
+ immutable_array(new_val, new_mark)
156
+ end
157
+
158
+ private
159
+
160
+ def immutable_array(*args)
161
+ args.freeze
162
+ end
163
+ end
164
+ end