o-concurrent-ruby 1.1.11

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 (142) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +542 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +404 -0
  6. data/Rakefile +307 -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 +189 -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/agent.rb +587 -0
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/concurrent-ruby/concurrent/async.rb +449 -0
  25. data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
  26. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  27. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  30. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  31. data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
  32. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
  33. data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
  34. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
  35. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
  36. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  37. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  38. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  39. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
  40. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
  41. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
  42. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
  43. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
  44. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
  45. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  46. data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  47. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  48. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  49. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  50. data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  51. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  52. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  53. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
  54. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  55. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  56. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  57. data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  58. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
  59. data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
  60. data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
  61. data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
  62. data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
  63. data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
  64. data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
  65. data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
  66. data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
  67. data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
  68. data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
  69. data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
  70. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
  71. data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
  72. data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
  73. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
  74. data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
  75. data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
  76. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
  77. data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
  78. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
  79. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
  80. data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
  81. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
  82. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
  83. data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
  84. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
  85. data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
  86. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
  87. data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
  88. data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
  89. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
  90. data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
  91. data/lib/concurrent-ruby/concurrent/future.rb +141 -0
  92. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  93. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
  94. data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
  95. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  96. data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
  97. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
  98. data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
  99. data/lib/concurrent-ruby/concurrent/options.rb +42 -0
  100. data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
  101. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  102. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  103. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
  104. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  105. data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
  106. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  107. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
  108. data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
  109. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
  110. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  111. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
  112. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
  113. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
  114. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
  115. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  116. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
  117. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
  118. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
  119. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  120. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
  121. data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
  122. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  123. data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
  124. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  125. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  126. data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  127. data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
  128. data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
  129. data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  130. data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
  131. data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
  132. data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
  133. data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
  134. data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
  135. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  136. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  137. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
  138. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
  139. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  140. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  141. data/lib/concurrent-ruby/concurrent.rb +134 -0
  142. metadata +192 -0
@@ -0,0 +1,166 @@
1
+ require 'concurrent/atomic/mutex_semaphore'
2
+ require 'concurrent/synchronization'
3
+
4
+ module Concurrent
5
+
6
+ ###################################################################
7
+
8
+ # @!macro semaphore_method_initialize
9
+ #
10
+ # Create a new `Semaphore` with the initial `count`.
11
+ #
12
+ # @param [Fixnum] count the initial count
13
+ #
14
+ # @raise [ArgumentError] if `count` is not an integer or is less than zero
15
+
16
+ # @!macro semaphore_method_acquire
17
+ #
18
+ # Acquires the given number of permits from this semaphore,
19
+ # blocking until all are available. If a block is given,
20
+ # yields to it and releases the permits afterwards.
21
+ #
22
+ # @param [Fixnum] permits Number of permits to acquire
23
+ #
24
+ # @raise [ArgumentError] if `permits` is not an integer or is less than
25
+ # one
26
+ #
27
+ # @return [nil, BasicObject] Without a block, `nil` is returned. If a block
28
+ # is given, its return value is returned.
29
+
30
+ # @!macro semaphore_method_available_permits
31
+ #
32
+ # Returns the current number of permits available in this semaphore.
33
+ #
34
+ # @return [Integer]
35
+
36
+ # @!macro semaphore_method_drain_permits
37
+ #
38
+ # Acquires and returns all permits that are immediately available.
39
+ #
40
+ # @return [Integer]
41
+
42
+ # @!macro semaphore_method_try_acquire
43
+ #
44
+ # Acquires the given number of permits from this semaphore,
45
+ # only if all are available at the time of invocation or within
46
+ # `timeout` interval. If a block is given, yields to it if the permits
47
+ # were successfully acquired, and releases them afterward, returning the
48
+ # block's return value.
49
+ #
50
+ # @param [Fixnum] permits the number of permits to acquire
51
+ #
52
+ # @param [Fixnum] timeout the number of seconds to wait for the counter
53
+ # or `nil` to return immediately
54
+ #
55
+ # @raise [ArgumentError] if `permits` is not an integer or is less than
56
+ # one
57
+ #
58
+ # @return [true, false, nil, BasicObject] `false` if no permits are
59
+ # available, `true` when acquired a permit. If a block is given, the
60
+ # block's return value is returned if the permits were acquired; if not,
61
+ # `nil` is returned.
62
+
63
+ # @!macro semaphore_method_release
64
+ #
65
+ # Releases the given number of permits, returning them to the semaphore.
66
+ #
67
+ # @param [Fixnum] permits Number of permits to return to the semaphore.
68
+ #
69
+ # @raise [ArgumentError] if `permits` is not a number or is less than one
70
+ #
71
+ # @return [nil]
72
+
73
+ ###################################################################
74
+
75
+ # @!macro semaphore_public_api
76
+ #
77
+ # @!method initialize(count)
78
+ # @!macro semaphore_method_initialize
79
+ #
80
+ # @!method acquire(permits = 1)
81
+ # @!macro semaphore_method_acquire
82
+ #
83
+ # @!method available_permits
84
+ # @!macro semaphore_method_available_permits
85
+ #
86
+ # @!method drain_permits
87
+ # @!macro semaphore_method_drain_permits
88
+ #
89
+ # @!method try_acquire(permits = 1, timeout = nil)
90
+ # @!macro semaphore_method_try_acquire
91
+ #
92
+ # @!method release(permits = 1)
93
+ # @!macro semaphore_method_release
94
+
95
+ ###################################################################
96
+
97
+ # @!visibility private
98
+ # @!macro internal_implementation_note
99
+ SemaphoreImplementation = case
100
+ when defined?(JavaSemaphore)
101
+ JavaSemaphore
102
+ else
103
+ MutexSemaphore
104
+ end
105
+ private_constant :SemaphoreImplementation
106
+
107
+ # @!macro semaphore
108
+ #
109
+ # A counting semaphore. Conceptually, a semaphore maintains a set of
110
+ # permits. Each {#acquire} blocks if necessary until a permit is
111
+ # available, and then takes it. Each {#release} adds a permit, potentially
112
+ # releasing a blocking acquirer.
113
+ # However, no actual permit objects are used; the Semaphore just keeps a
114
+ # count of the number available and acts accordingly.
115
+ # Alternatively, permits may be acquired within a block, and automatically
116
+ # released after the block finishes executing.
117
+ #
118
+ # @!macro semaphore_public_api
119
+ # @example
120
+ # semaphore = Concurrent::Semaphore.new(2)
121
+ #
122
+ # t1 = Thread.new do
123
+ # semaphore.acquire
124
+ # puts "Thread 1 acquired semaphore"
125
+ # end
126
+ #
127
+ # t2 = Thread.new do
128
+ # semaphore.acquire
129
+ # puts "Thread 2 acquired semaphore"
130
+ # end
131
+ #
132
+ # t3 = Thread.new do
133
+ # semaphore.acquire
134
+ # puts "Thread 3 acquired semaphore"
135
+ # end
136
+ #
137
+ # t4 = Thread.new do
138
+ # sleep(2)
139
+ # puts "Thread 4 releasing semaphore"
140
+ # semaphore.release
141
+ # end
142
+ #
143
+ # [t1, t2, t3, t4].each(&:join)
144
+ #
145
+ # # prints:
146
+ # # Thread 3 acquired semaphore
147
+ # # Thread 2 acquired semaphore
148
+ # # Thread 4 releasing semaphore
149
+ # # Thread 1 acquired semaphore
150
+ #
151
+ # @example
152
+ # semaphore = Concurrent::Semaphore.new(1)
153
+ #
154
+ # puts semaphore.available_permits
155
+ # semaphore.acquire do
156
+ # puts semaphore.available_permits
157
+ # end
158
+ # puts semaphore.available_permits
159
+ #
160
+ # # prints:
161
+ # # 1
162
+ # # 0
163
+ # # 1
164
+ class Semaphore < SemaphoreImplementation
165
+ end
166
+ end
@@ -0,0 +1,104 @@
1
+ require 'concurrent/utility/engine'
2
+ require 'concurrent/atomic/ruby_thread_local_var'
3
+ require 'concurrent/atomic/java_thread_local_var'
4
+
5
+ module Concurrent
6
+
7
+ ###################################################################
8
+
9
+ # @!macro thread_local_var_method_initialize
10
+ #
11
+ # Creates a thread local variable.
12
+ #
13
+ # @param [Object] default the default value when otherwise unset
14
+ # @param [Proc] default_block Optional block that gets called to obtain the
15
+ # default value for each thread
16
+
17
+ # @!macro thread_local_var_method_get
18
+ #
19
+ # Returns the value in the current thread's copy of this thread-local variable.
20
+ #
21
+ # @return [Object] the current value
22
+
23
+ # @!macro thread_local_var_method_set
24
+ #
25
+ # Sets the current thread's copy of this thread-local variable to the specified value.
26
+ #
27
+ # @param [Object] value the value to set
28
+ # @return [Object] the new value
29
+
30
+ # @!macro thread_local_var_method_bind
31
+ #
32
+ # Bind the given value to thread local storage during
33
+ # execution of the given block.
34
+ #
35
+ # @param [Object] value the value to bind
36
+ # @yield the operation to be performed with the bound variable
37
+ # @return [Object] the value
38
+
39
+
40
+ ###################################################################
41
+
42
+ # @!macro thread_local_var_public_api
43
+ #
44
+ # @!method initialize(default = nil, &default_block)
45
+ # @!macro thread_local_var_method_initialize
46
+ #
47
+ # @!method value
48
+ # @!macro thread_local_var_method_get
49
+ #
50
+ # @!method value=(value)
51
+ # @!macro thread_local_var_method_set
52
+ #
53
+ # @!method bind(value, &block)
54
+ # @!macro thread_local_var_method_bind
55
+
56
+ ###################################################################
57
+
58
+ # @!visibility private
59
+ # @!macro internal_implementation_note
60
+ ThreadLocalVarImplementation = case
61
+ when Concurrent.on_jruby?
62
+ JavaThreadLocalVar
63
+ else
64
+ RubyThreadLocalVar
65
+ end
66
+ private_constant :ThreadLocalVarImplementation
67
+
68
+ # @!macro thread_local_var
69
+ #
70
+ # A `ThreadLocalVar` is a variable where the value is different for each thread.
71
+ # Each variable may have a default value, but when you modify the variable only
72
+ # the current thread will ever see that change.
73
+ #
74
+ # @!macro thread_safe_variable_comparison
75
+ #
76
+ # @example
77
+ # v = ThreadLocalVar.new(14)
78
+ # v.value #=> 14
79
+ # v.value = 2
80
+ # v.value #=> 2
81
+ #
82
+ # @example
83
+ # v = ThreadLocalVar.new(14)
84
+ #
85
+ # t1 = Thread.new do
86
+ # v.value #=> 14
87
+ # v.value = 1
88
+ # v.value #=> 1
89
+ # end
90
+ #
91
+ # t2 = Thread.new do
92
+ # v.value #=> 14
93
+ # v.value = 2
94
+ # v.value #=> 2
95
+ # end
96
+ #
97
+ # v.value #=> 14
98
+ #
99
+ # @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal
100
+ #
101
+ # @!macro thread_local_var_public_api
102
+ class ThreadLocalVar < ThreadLocalVarImplementation
103
+ end
104
+ end
@@ -0,0 +1,56 @@
1
+ module Concurrent
2
+
3
+ # @!visibility private
4
+ # @!macro internal_implementation_note
5
+ class MutexAtomicReference < Synchronization::LockableObject
6
+ include AtomicDirectUpdate
7
+ include AtomicNumericCompareAndSetWrapper
8
+ alias_method :compare_and_swap, :compare_and_set
9
+
10
+ # @!macro atomic_reference_method_initialize
11
+ def initialize(value = nil)
12
+ super()
13
+ synchronize { ns_initialize(value) }
14
+ end
15
+
16
+ # @!macro atomic_reference_method_get
17
+ def get
18
+ synchronize { @value }
19
+ end
20
+ alias_method :value, :get
21
+
22
+ # @!macro atomic_reference_method_set
23
+ def set(new_value)
24
+ synchronize { @value = new_value }
25
+ end
26
+ alias_method :value=, :set
27
+
28
+ # @!macro atomic_reference_method_get_and_set
29
+ def get_and_set(new_value)
30
+ synchronize do
31
+ old_value = @value
32
+ @value = new_value
33
+ old_value
34
+ end
35
+ end
36
+ alias_method :swap, :get_and_set
37
+
38
+ # @!macro atomic_reference_method_compare_and_set
39
+ def _compare_and_set(old_value, new_value)
40
+ synchronize do
41
+ if @value.equal? old_value
42
+ @value = new_value
43
+ true
44
+ else
45
+ false
46
+ end
47
+ end
48
+ end
49
+
50
+ protected
51
+
52
+ def ns_initialize(value)
53
+ @value = value
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,28 @@
1
+ module Concurrent
2
+
3
+ # Special "compare and set" handling of numeric values.
4
+ #
5
+ # @!visibility private
6
+ # @!macro internal_implementation_note
7
+ module AtomicNumericCompareAndSetWrapper
8
+
9
+ # @!macro atomic_reference_method_compare_and_set
10
+ def compare_and_set(old_value, new_value)
11
+ if old_value.kind_of? Numeric
12
+ while true
13
+ old = get
14
+
15
+ return false unless old.kind_of? Numeric
16
+
17
+ return false unless old == old_value
18
+
19
+ result = _compare_and_set(old, new_value)
20
+ return result if result
21
+ end
22
+ else
23
+ _compare_and_set(old_value, new_value)
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ require 'concurrent/atomic/atomic_reference'
2
+ require 'concurrent/atomic/atomic_boolean'
3
+ require 'concurrent/atomic/atomic_fixnum'
4
+ require 'concurrent/atomic/cyclic_barrier'
5
+ require 'concurrent/atomic/count_down_latch'
6
+ require 'concurrent/atomic/event'
7
+ require 'concurrent/atomic/read_write_lock'
8
+ require 'concurrent/atomic/reentrant_read_write_lock'
9
+ require 'concurrent/atomic/semaphore'
10
+ require 'concurrent/atomic/thread_local_var'
@@ -0,0 +1,107 @@
1
+ require 'concurrent/synchronization'
2
+
3
+ module Concurrent
4
+ module Collection
5
+
6
+ # A thread safe observer set implemented using copy-on-read approach:
7
+ # observers are added and removed from a thread safe collection; every time
8
+ # a notification is required the internal data structure is copied to
9
+ # prevent concurrency issues
10
+ #
11
+ # @api private
12
+ class CopyOnNotifyObserverSet < Synchronization::LockableObject
13
+
14
+ def initialize
15
+ super()
16
+ synchronize { ns_initialize }
17
+ end
18
+
19
+ # @!macro observable_add_observer
20
+ def add_observer(observer = nil, func = :update, &block)
21
+ if observer.nil? && block.nil?
22
+ raise ArgumentError, 'should pass observer as a first argument or block'
23
+ elsif observer && block
24
+ raise ArgumentError.new('cannot provide both an observer and a block')
25
+ end
26
+
27
+ if block
28
+ observer = block
29
+ func = :call
30
+ end
31
+
32
+ synchronize do
33
+ @observers[observer] = func
34
+ observer
35
+ end
36
+ end
37
+
38
+ # @!macro observable_delete_observer
39
+ def delete_observer(observer)
40
+ synchronize do
41
+ @observers.delete(observer)
42
+ observer
43
+ end
44
+ end
45
+
46
+ # @!macro observable_delete_observers
47
+ def delete_observers
48
+ synchronize do
49
+ @observers.clear
50
+ self
51
+ end
52
+ end
53
+
54
+ # @!macro observable_count_observers
55
+ def count_observers
56
+ synchronize { @observers.count }
57
+ end
58
+
59
+ # Notifies all registered observers with optional args
60
+ # @param [Object] args arguments to be passed to each observer
61
+ # @return [CopyOnWriteObserverSet] self
62
+ def notify_observers(*args, &block)
63
+ observers = duplicate_observers
64
+ notify_to(observers, *args, &block)
65
+ self
66
+ end
67
+
68
+ # Notifies all registered observers with optional args and deletes them.
69
+ #
70
+ # @param [Object] args arguments to be passed to each observer
71
+ # @return [CopyOnWriteObserverSet] self
72
+ def notify_and_delete_observers(*args, &block)
73
+ observers = duplicate_and_clear_observers
74
+ notify_to(observers, *args, &block)
75
+ self
76
+ end
77
+
78
+ protected
79
+
80
+ def ns_initialize
81
+ @observers = {}
82
+ end
83
+
84
+ private
85
+
86
+ def duplicate_and_clear_observers
87
+ synchronize do
88
+ observers = @observers.dup
89
+ @observers.clear
90
+ observers
91
+ end
92
+ end
93
+
94
+ def duplicate_observers
95
+ synchronize { @observers.dup }
96
+ end
97
+
98
+ def notify_to(observers, *args)
99
+ raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty?
100
+ observers.each do |observer, function|
101
+ args = yield if block_given?
102
+ observer.send(function, *args)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,111 @@
1
+ require 'concurrent/synchronization'
2
+
3
+ module Concurrent
4
+ module Collection
5
+
6
+ # A thread safe observer set implemented using copy-on-write approach:
7
+ # every time an observer is added or removed the whole internal data structure is
8
+ # duplicated and replaced with a new one.
9
+ #
10
+ # @api private
11
+ class CopyOnWriteObserverSet < Synchronization::LockableObject
12
+
13
+ def initialize
14
+ super()
15
+ synchronize { ns_initialize }
16
+ end
17
+
18
+ # @!macro observable_add_observer
19
+ def add_observer(observer = nil, func = :update, &block)
20
+ if observer.nil? && block.nil?
21
+ raise ArgumentError, 'should pass observer as a first argument or block'
22
+ elsif observer && block
23
+ raise ArgumentError.new('cannot provide both an observer and a block')
24
+ end
25
+
26
+ if block
27
+ observer = block
28
+ func = :call
29
+ end
30
+
31
+ synchronize do
32
+ new_observers = @observers.dup
33
+ new_observers[observer] = func
34
+ @observers = new_observers
35
+ observer
36
+ end
37
+ end
38
+
39
+ # @!macro observable_delete_observer
40
+ def delete_observer(observer)
41
+ synchronize do
42
+ new_observers = @observers.dup
43
+ new_observers.delete(observer)
44
+ @observers = new_observers
45
+ observer
46
+ end
47
+ end
48
+
49
+ # @!macro observable_delete_observers
50
+ def delete_observers
51
+ self.observers = {}
52
+ self
53
+ end
54
+
55
+ # @!macro observable_count_observers
56
+ def count_observers
57
+ observers.count
58
+ end
59
+
60
+ # Notifies all registered observers with optional args
61
+ # @param [Object] args arguments to be passed to each observer
62
+ # @return [CopyOnWriteObserverSet] self
63
+ def notify_observers(*args, &block)
64
+ notify_to(observers, *args, &block)
65
+ self
66
+ end
67
+
68
+ # Notifies all registered observers with optional args and deletes them.
69
+ #
70
+ # @param [Object] args arguments to be passed to each observer
71
+ # @return [CopyOnWriteObserverSet] self
72
+ def notify_and_delete_observers(*args, &block)
73
+ old = clear_observers_and_return_old
74
+ notify_to(old, *args, &block)
75
+ self
76
+ end
77
+
78
+ protected
79
+
80
+ def ns_initialize
81
+ @observers = {}
82
+ end
83
+
84
+ private
85
+
86
+ def notify_to(observers, *args)
87
+ raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty?
88
+ observers.each do |observer, function|
89
+ args = yield if block_given?
90
+ observer.send(function, *args)
91
+ end
92
+ end
93
+
94
+ def observers
95
+ synchronize { @observers }
96
+ end
97
+
98
+ def observers=(new_set)
99
+ synchronize { @observers = new_set }
100
+ end
101
+
102
+ def clear_observers_and_return_old
103
+ synchronize do
104
+ old_observers = @observers
105
+ @observers = {}
106
+ old_observers
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,84 @@
1
+ if Concurrent.on_jruby?
2
+
3
+ module Concurrent
4
+ module Collection
5
+
6
+
7
+ # @!macro priority_queue
8
+ #
9
+ # @!visibility private
10
+ # @!macro internal_implementation_note
11
+ class JavaNonConcurrentPriorityQueue
12
+
13
+ # @!macro priority_queue_method_initialize
14
+ def initialize(opts = {})
15
+ order = opts.fetch(:order, :max)
16
+ if [:min, :low].include?(order)
17
+ @queue = java.util.PriorityQueue.new(11) # 11 is the default initial capacity
18
+ else
19
+ @queue = java.util.PriorityQueue.new(11, java.util.Collections.reverseOrder())
20
+ end
21
+ end
22
+
23
+ # @!macro priority_queue_method_clear
24
+ def clear
25
+ @queue.clear
26
+ true
27
+ end
28
+
29
+ # @!macro priority_queue_method_delete
30
+ def delete(item)
31
+ found = false
32
+ while @queue.remove(item) do
33
+ found = true
34
+ end
35
+ found
36
+ end
37
+
38
+ # @!macro priority_queue_method_empty
39
+ def empty?
40
+ @queue.size == 0
41
+ end
42
+
43
+ # @!macro priority_queue_method_include
44
+ def include?(item)
45
+ @queue.contains(item)
46
+ end
47
+ alias_method :has_priority?, :include?
48
+
49
+ # @!macro priority_queue_method_length
50
+ def length
51
+ @queue.size
52
+ end
53
+ alias_method :size, :length
54
+
55
+ # @!macro priority_queue_method_peek
56
+ def peek
57
+ @queue.peek
58
+ end
59
+
60
+ # @!macro priority_queue_method_pop
61
+ def pop
62
+ @queue.poll
63
+ end
64
+ alias_method :deq, :pop
65
+ alias_method :shift, :pop
66
+
67
+ # @!macro priority_queue_method_push
68
+ def push(item)
69
+ raise ArgumentError.new('cannot enqueue nil') if item.nil?
70
+ @queue.add(item)
71
+ end
72
+ alias_method :<<, :push
73
+ alias_method :enq, :push
74
+
75
+ # @!macro priority_queue_method_from_list
76
+ def self.from_list(list, opts = {})
77
+ queue = new(opts)
78
+ list.each{|item| queue << item }
79
+ queue
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end