concurrent-ruby 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +478 -0
  3. data/Gemfile +41 -0
  4. data/LICENSE.md +23 -0
  5. data/README.md +381 -0
  6. data/Rakefile +327 -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.rb +1 -0
  23. data/lib/concurrent.rb +134 -0
  24. data/lib/concurrent/agent.rb +587 -0
  25. data/lib/concurrent/array.rb +66 -0
  26. data/lib/concurrent/async.rb +459 -0
  27. data/lib/concurrent/atom.rb +222 -0
  28. data/lib/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  29. data/lib/concurrent/atomic/atomic_boolean.rb +126 -0
  30. data/lib/concurrent/atomic/atomic_fixnum.rb +143 -0
  31. data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
  32. data/lib/concurrent/atomic/atomic_reference.rb +204 -0
  33. data/lib/concurrent/atomic/count_down_latch.rb +100 -0
  34. data/lib/concurrent/atomic/cyclic_barrier.rb +128 -0
  35. data/lib/concurrent/atomic/event.rb +109 -0
  36. data/lib/concurrent/atomic/java_count_down_latch.rb +42 -0
  37. data/lib/concurrent/atomic/java_thread_local_var.rb +37 -0
  38. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  39. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  40. data/lib/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  41. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  42. data/lib/concurrent/atomic/read_write_lock.rb +254 -0
  43. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +379 -0
  44. data/lib/concurrent/atomic/ruby_thread_local_var.rb +161 -0
  45. data/lib/concurrent/atomic/semaphore.rb +145 -0
  46. data/lib/concurrent/atomic/thread_local_var.rb +104 -0
  47. data/lib/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  48. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  49. data/lib/concurrent/atomics.rb +10 -0
  50. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  51. data/lib/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  52. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  53. data/lib/concurrent/collection/lock_free_stack.rb +158 -0
  54. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  55. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  56. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  57. data/lib/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  58. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  59. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  60. data/lib/concurrent/concern/deprecation.rb +34 -0
  61. data/lib/concurrent/concern/dereferenceable.rb +73 -0
  62. data/lib/concurrent/concern/logging.rb +32 -0
  63. data/lib/concurrent/concern/obligation.rb +220 -0
  64. data/lib/concurrent/concern/observable.rb +110 -0
  65. data/lib/concurrent/concurrent_ruby.jar +0 -0
  66. data/lib/concurrent/configuration.rb +184 -0
  67. data/lib/concurrent/constants.rb +8 -0
  68. data/lib/concurrent/dataflow.rb +81 -0
  69. data/lib/concurrent/delay.rb +199 -0
  70. data/lib/concurrent/errors.rb +69 -0
  71. data/lib/concurrent/exchanger.rb +352 -0
  72. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  73. data/lib/concurrent/executor/cached_thread_pool.rb +62 -0
  74. data/lib/concurrent/executor/executor_service.rb +185 -0
  75. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -0
  76. data/lib/concurrent/executor/immediate_executor.rb +66 -0
  77. data/lib/concurrent/executor/indirect_immediate_executor.rb +44 -0
  78. data/lib/concurrent/executor/java_executor_service.rb +91 -0
  79. data/lib/concurrent/executor/java_single_thread_executor.rb +29 -0
  80. data/lib/concurrent/executor/java_thread_pool_executor.rb +123 -0
  81. data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
  82. data/lib/concurrent/executor/ruby_single_thread_executor.rb +22 -0
  83. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +362 -0
  84. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  85. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  86. data/lib/concurrent/executor/serialized_execution.rb +107 -0
  87. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  88. data/lib/concurrent/executor/simple_executor_service.rb +100 -0
  89. data/lib/concurrent/executor/single_thread_executor.rb +56 -0
  90. data/lib/concurrent/executor/thread_pool_executor.rb +87 -0
  91. data/lib/concurrent/executor/timer_set.rb +173 -0
  92. data/lib/concurrent/executors.rb +20 -0
  93. data/lib/concurrent/future.rb +141 -0
  94. data/lib/concurrent/hash.rb +59 -0
  95. data/lib/concurrent/immutable_struct.rb +93 -0
  96. data/lib/concurrent/ivar.rb +207 -0
  97. data/lib/concurrent/map.rb +337 -0
  98. data/lib/concurrent/maybe.rb +229 -0
  99. data/lib/concurrent/mutable_struct.rb +229 -0
  100. data/lib/concurrent/mvar.rb +242 -0
  101. data/lib/concurrent/options.rb +42 -0
  102. data/lib/concurrent/promise.rb +579 -0
  103. data/lib/concurrent/promises.rb +2167 -0
  104. data/lib/concurrent/re_include.rb +58 -0
  105. data/lib/concurrent/scheduled_task.rb +318 -0
  106. data/lib/concurrent/set.rb +66 -0
  107. data/lib/concurrent/settable_struct.rb +129 -0
  108. data/lib/concurrent/synchronization.rb +30 -0
  109. data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  110. data/lib/concurrent/synchronization/abstract_object.rb +24 -0
  111. data/lib/concurrent/synchronization/abstract_struct.rb +160 -0
  112. data/lib/concurrent/synchronization/condition.rb +60 -0
  113. data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  114. data/lib/concurrent/synchronization/jruby_object.rb +45 -0
  115. data/lib/concurrent/synchronization/lock.rb +36 -0
  116. data/lib/concurrent/synchronization/lockable_object.rb +74 -0
  117. data/lib/concurrent/synchronization/mri_object.rb +44 -0
  118. data/lib/concurrent/synchronization/mutex_lockable_object.rb +76 -0
  119. data/lib/concurrent/synchronization/object.rb +183 -0
  120. data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
  121. data/lib/concurrent/synchronization/rbx_object.rb +49 -0
  122. data/lib/concurrent/synchronization/truffleruby_object.rb +47 -0
  123. data/lib/concurrent/synchronization/volatile.rb +36 -0
  124. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  125. data/lib/concurrent/thread_safe/util.rb +16 -0
  126. data/lib/concurrent/thread_safe/util/adder.rb +74 -0
  127. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  128. data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
  129. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  130. data/lib/concurrent/thread_safe/util/striped64.rb +246 -0
  131. data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
  132. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  133. data/lib/concurrent/timer_task.rb +334 -0
  134. data/lib/concurrent/tuple.rb +86 -0
  135. data/lib/concurrent/tvar.rb +258 -0
  136. data/lib/concurrent/utility/at_exit.rb +97 -0
  137. data/lib/concurrent/utility/engine.rb +56 -0
  138. data/lib/concurrent/utility/monotonic_time.rb +58 -0
  139. data/lib/concurrent/utility/native_extension_loader.rb +79 -0
  140. data/lib/concurrent/utility/native_integer.rb +53 -0
  141. data/lib/concurrent/utility/processor_counter.rb +158 -0
  142. data/lib/concurrent/version.rb +3 -0
  143. metadata +193 -0
@@ -0,0 +1,58 @@
1
+ module Concurrent
2
+
3
+ # Methods form module A included to a module B, which is already included into class C,
4
+ # will not be visible in the C class. If this module is extended to B then A's methods
5
+ # are correctly made visible to C.
6
+ #
7
+ # @example
8
+ # module A
9
+ # def a
10
+ # :a
11
+ # end
12
+ # end
13
+ #
14
+ # module B1
15
+ # end
16
+ #
17
+ # class C1
18
+ # include B1
19
+ # end
20
+ #
21
+ # module B2
22
+ # extend Concurrent::ReInclude
23
+ # end
24
+ #
25
+ # class C2
26
+ # include B2
27
+ # end
28
+ #
29
+ # B1.send :include, A
30
+ # B2.send :include, A
31
+ #
32
+ # C1.new.respond_to? :a # => false
33
+ # C2.new.respond_to? :a # => true
34
+ module ReInclude
35
+ # @!visibility private
36
+ def included(base)
37
+ (@re_include_to_bases ||= []) << [:include, base]
38
+ super(base)
39
+ end
40
+
41
+ # @!visibility private
42
+ def extended(base)
43
+ (@re_include_to_bases ||= []) << [:extend, base]
44
+ super(base)
45
+ end
46
+
47
+ # @!visibility private
48
+ def include(*modules)
49
+ result = super(*modules)
50
+ modules.reverse.each do |module_being_included|
51
+ (@re_include_to_bases ||= []).each do |method, mod|
52
+ mod.send method, module_being_included
53
+ end
54
+ end
55
+ result
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,318 @@
1
+ require 'concurrent/constants'
2
+ require 'concurrent/errors'
3
+ require 'concurrent/configuration'
4
+ require 'concurrent/ivar'
5
+ require 'concurrent/collection/copy_on_notify_observer_set'
6
+ require 'concurrent/utility/monotonic_time'
7
+
8
+ require 'concurrent/options'
9
+
10
+ module Concurrent
11
+
12
+ # `ScheduledTask` is a close relative of `Concurrent::Future` but with one
13
+ # important difference: A `Future` is set to execute as soon as possible
14
+ # whereas a `ScheduledTask` is set to execute after a specified delay. This
15
+ # implementation is loosely based on Java's
16
+ # [ScheduledExecutorService](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html).
17
+ # It is a more feature-rich variant of {Concurrent.timer}.
18
+ #
19
+ # The *intended* schedule time of task execution is set on object construction
20
+ # with the `delay` argument. The delay is a numeric (floating point or integer)
21
+ # representing a number of seconds in the future. Any other value or a numeric
22
+ # equal to or less than zero will result in an exception. The *actual* schedule
23
+ # time of task execution is set when the `execute` method is called.
24
+ #
25
+ # The constructor can also be given zero or more processing options. Currently
26
+ # the only supported options are those recognized by the
27
+ # [Dereferenceable](Dereferenceable) module.
28
+ #
29
+ # The final constructor argument is a block representing the task to be performed.
30
+ # If no block is given an `ArgumentError` will be raised.
31
+ #
32
+ # **States**
33
+ #
34
+ # `ScheduledTask` mixes in the [Obligation](Obligation) module thus giving it
35
+ # "future" behavior. This includes the expected lifecycle states. `ScheduledTask`
36
+ # has one additional state, however. While the task (block) is being executed the
37
+ # state of the object will be `:processing`. This additional state is necessary
38
+ # because it has implications for task cancellation.
39
+ #
40
+ # **Cancellation**
41
+ #
42
+ # A `:pending` task can be cancelled using the `#cancel` method. A task in any
43
+ # other state, including `:processing`, cannot be cancelled. The `#cancel`
44
+ # method returns a boolean indicating the success of the cancellation attempt.
45
+ # A cancelled `ScheduledTask` cannot be restarted. It is immutable.
46
+ #
47
+ # **Obligation and Observation**
48
+ #
49
+ # The result of a `ScheduledTask` can be obtained either synchronously or
50
+ # asynchronously. `ScheduledTask` mixes in both the [Obligation](Obligation)
51
+ # module and the
52
+ # [Observable](http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html)
53
+ # module from the Ruby standard library. With one exception `ScheduledTask`
54
+ # behaves identically to [Future](Observable) with regard to these modules.
55
+ #
56
+ # @!macro copy_options
57
+ #
58
+ # @example Basic usage
59
+ #
60
+ # require 'concurrent'
61
+ # require 'thread' # for Queue
62
+ # require 'open-uri' # for open(uri)
63
+ #
64
+ # class Ticker
65
+ # def get_year_end_closing(symbol, year)
66
+ # uri = "http://ichart.finance.yahoo.com/table.csv?s=#{symbol}&a=11&b=01&c=#{year}&d=11&e=31&f=#{year}&g=m"
67
+ # data = open(uri) {|f| f.collect{|line| line.strip } }
68
+ # data[1].split(',')[4].to_f
69
+ # end
70
+ # end
71
+ #
72
+ # # Future
73
+ # price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013) }
74
+ # price.state #=> :pending
75
+ # sleep(1) # do other stuff
76
+ # price.value #=> 63.65
77
+ # price.state #=> :fulfilled
78
+ #
79
+ # # ScheduledTask
80
+ # task = Concurrent::ScheduledTask.execute(2){ Ticker.new.get_year_end_closing('INTC', 2013) }
81
+ # task.state #=> :pending
82
+ # sleep(3) # do other stuff
83
+ # task.value #=> 25.96
84
+ #
85
+ # @example Successful task execution
86
+ #
87
+ # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }
88
+ # task.state #=> :unscheduled
89
+ # task.execute
90
+ # task.state #=> pending
91
+ #
92
+ # # wait for it...
93
+ # sleep(3)
94
+ #
95
+ # task.unscheduled? #=> false
96
+ # task.pending? #=> false
97
+ # task.fulfilled? #=> true
98
+ # task.rejected? #=> false
99
+ # task.value #=> 'What does the fox say?'
100
+ #
101
+ # @example One line creation and execution
102
+ #
103
+ # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }.execute
104
+ # task.state #=> pending
105
+ #
106
+ # task = Concurrent::ScheduledTask.execute(2){ 'What do you get when you multiply 6 by 9?' }
107
+ # task.state #=> pending
108
+ #
109
+ # @example Failed task execution
110
+ #
111
+ # task = Concurrent::ScheduledTask.execute(2){ raise StandardError.new('Call me maybe?') }
112
+ # task.pending? #=> true
113
+ #
114
+ # # wait for it...
115
+ # sleep(3)
116
+ #
117
+ # task.unscheduled? #=> false
118
+ # task.pending? #=> false
119
+ # task.fulfilled? #=> false
120
+ # task.rejected? #=> true
121
+ # task.value #=> nil
122
+ # task.reason #=> #<StandardError: Call me maybe?>
123
+ #
124
+ # @example Task execution with observation
125
+ #
126
+ # observer = Class.new{
127
+ # def update(time, value, reason)
128
+ # puts "The task completed at #{time} with value '#{value}'"
129
+ # end
130
+ # }.new
131
+ #
132
+ # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }
133
+ # task.add_observer(observer)
134
+ # task.execute
135
+ # task.pending? #=> true
136
+ #
137
+ # # wait for it...
138
+ # sleep(3)
139
+ #
140
+ # #>> The task completed at 2013-11-07 12:26:09 -0500 with value 'What does the fox say?'
141
+ #
142
+ # @!macro monotonic_clock_warning
143
+ #
144
+ # @see Concurrent.timer
145
+ class ScheduledTask < IVar
146
+ include Comparable
147
+
148
+ # The executor on which to execute the task.
149
+ # @!visibility private
150
+ attr_reader :executor
151
+
152
+ # Schedule a task for execution at a specified future time.
153
+ #
154
+ # @param [Float] delay the number of seconds to wait for before executing the task
155
+ #
156
+ # @yield the task to be performed
157
+ #
158
+ # @!macro executor_and_deref_options
159
+ #
160
+ # @option opts [object, Array] :args zero or more arguments to be passed the task
161
+ # block on execution
162
+ #
163
+ # @raise [ArgumentError] When no block is given
164
+ # @raise [ArgumentError] When given a time that is in the past
165
+ def initialize(delay, opts = {}, &task)
166
+ raise ArgumentError.new('no block given') unless block_given?
167
+ raise ArgumentError.new('seconds must be greater than zero') if delay.to_f < 0.0
168
+
169
+ super(NULL, opts, &nil)
170
+
171
+ synchronize do
172
+ ns_set_state(:unscheduled)
173
+ @parent = opts.fetch(:timer_set, Concurrent.global_timer_set)
174
+ @args = get_arguments_from(opts)
175
+ @delay = delay.to_f
176
+ @task = task
177
+ @time = nil
178
+ @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor
179
+ self.observers = Collection::CopyOnNotifyObserverSet.new
180
+ end
181
+ end
182
+
183
+ # The `delay` value given at instanciation.
184
+ #
185
+ # @return [Float] the initial delay.
186
+ def initial_delay
187
+ synchronize { @delay }
188
+ end
189
+
190
+ # The monotonic time at which the the task is scheduled to be executed.
191
+ #
192
+ # @return [Float] the schedule time or nil if `unscheduled`
193
+ def schedule_time
194
+ synchronize { @time }
195
+ end
196
+
197
+ # Comparator which orders by schedule time.
198
+ #
199
+ # @!visibility private
200
+ def <=>(other)
201
+ schedule_time <=> other.schedule_time
202
+ end
203
+
204
+ # Has the task been cancelled?
205
+ #
206
+ # @return [Boolean] true if the task is in the given state else false
207
+ def cancelled?
208
+ synchronize { ns_check_state?(:cancelled) }
209
+ end
210
+
211
+ # In the task execution in progress?
212
+ #
213
+ # @return [Boolean] true if the task is in the given state else false
214
+ def processing?
215
+ synchronize { ns_check_state?(:processing) }
216
+ end
217
+
218
+ # Cancel this task and prevent it from executing. A task can only be
219
+ # cancelled if it is pending or unscheduled.
220
+ #
221
+ # @return [Boolean] true if successfully cancelled else false
222
+ def cancel
223
+ if compare_and_set_state(:cancelled, :pending, :unscheduled)
224
+ complete(false, nil, CancelledOperationError.new)
225
+ # To avoid deadlocks this call must occur outside of #synchronize
226
+ # Changing the state above should prevent redundant calls
227
+ @parent.send(:remove_task, self)
228
+ else
229
+ false
230
+ end
231
+ end
232
+
233
+ # Reschedule the task using the original delay and the current time.
234
+ # A task can only be reset while it is `:pending`.
235
+ #
236
+ # @return [Boolean] true if successfully rescheduled else false
237
+ def reset
238
+ synchronize{ ns_reschedule(@delay) }
239
+ end
240
+
241
+ # Reschedule the task using the given delay and the current time.
242
+ # A task can only be reset while it is `:pending`.
243
+ #
244
+ # @param [Float] delay the number of seconds to wait for before executing the task
245
+ #
246
+ # @return [Boolean] true if successfully rescheduled else false
247
+ #
248
+ # @raise [ArgumentError] When given a time that is in the past
249
+ def reschedule(delay)
250
+ delay = delay.to_f
251
+ raise ArgumentError.new('seconds must be greater than zero') if delay < 0.0
252
+ synchronize{ ns_reschedule(delay) }
253
+ end
254
+
255
+ # Execute an `:unscheduled` `ScheduledTask`. Immediately sets the state to `:pending`
256
+ # and starts counting down toward execution. Does nothing if the `ScheduledTask` is
257
+ # in any state other than `:unscheduled`.
258
+ #
259
+ # @return [ScheduledTask] a reference to `self`
260
+ def execute
261
+ if compare_and_set_state(:pending, :unscheduled)
262
+ synchronize{ ns_schedule(@delay) }
263
+ end
264
+ self
265
+ end
266
+
267
+ # Create a new `ScheduledTask` object with the given block, execute it, and return the
268
+ # `:pending` object.
269
+ #
270
+ # @param [Float] delay the number of seconds to wait for before executing the task
271
+ #
272
+ # @!macro executor_and_deref_options
273
+ #
274
+ # @return [ScheduledTask] the newly created `ScheduledTask` in the `:pending` state
275
+ #
276
+ # @raise [ArgumentError] if no block is given
277
+ def self.execute(delay, opts = {}, &task)
278
+ new(delay, opts, &task).execute
279
+ end
280
+
281
+ # Execute the task.
282
+ #
283
+ # @!visibility private
284
+ def process_task
285
+ safe_execute(@task, @args)
286
+ end
287
+
288
+ protected :set, :try_set, :fail, :complete
289
+
290
+ protected
291
+
292
+ # Schedule the task using the given delay and the current time.
293
+ #
294
+ # @param [Float] delay the number of seconds to wait for before executing the task
295
+ #
296
+ # @return [Boolean] true if successfully rescheduled else false
297
+ #
298
+ # @!visibility private
299
+ def ns_schedule(delay)
300
+ @delay = delay
301
+ @time = Concurrent.monotonic_time + @delay
302
+ @parent.send(:post_task, self)
303
+ end
304
+
305
+ # Reschedule the task using the given delay and the current time.
306
+ # A task can only be reset while it is `:pending`.
307
+ #
308
+ # @param [Float] delay the number of seconds to wait for before executing the task
309
+ #
310
+ # @return [Boolean] true if successfully rescheduled else false
311
+ #
312
+ # @!visibility private
313
+ def ns_reschedule(delay)
314
+ return false unless ns_check_state?(:pending)
315
+ @parent.send(:remove_task, self) && ns_schedule(delay)
316
+ end
317
+ end
318
+ end
@@ -0,0 +1,66 @@
1
+ require 'concurrent/utility/engine'
2
+ require 'concurrent/thread_safe/util'
3
+ require 'set'
4
+
5
+ module Concurrent
6
+
7
+ # @!macro concurrent_set
8
+ #
9
+ # A thread-safe subclass of Set. 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
+ #
13
+ # @note `a += b` is **not** a **thread-safe** operation on
14
+ # `Concurrent::Set`. It reads Set `a`, then it creates new `Concurrent::Set`
15
+ # which is union of `a` and `b`, then it writes the union to `a`.
16
+ # The read and write are independent operations they do not form a single atomic
17
+ # operation therefore when two `+=` operations are executed concurrently updates
18
+ # may be lost. Use `#merge` instead.
19
+ #
20
+ # @see http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html Ruby standard library `Set`
21
+
22
+
23
+ # @!macro internal_implementation_note
24
+ SetImplementation = case
25
+ when Concurrent.on_cruby?
26
+ # Because MRI never runs code in parallel, the existing
27
+ # non-thread-safe structures should usually work fine.
28
+ ::Set
29
+
30
+ when Concurrent.on_jruby?
31
+ require 'jruby/synchronized'
32
+
33
+ class JRubySet < ::Set
34
+ include JRuby::Synchronized
35
+ end
36
+ JRubySet
37
+
38
+ when Concurrent.on_rbx?
39
+ require 'monitor'
40
+ require 'concurrent/thread_safe/util/data_structures'
41
+
42
+ class RbxSet < ::Set
43
+ end
44
+ ThreadSafe::Util.make_synchronized_on_rbx Concurrent::RbxSet
45
+ RbxSet
46
+
47
+ when Concurrent.on_truffleruby?
48
+ require 'concurrent/thread_safe/util/data_structures'
49
+
50
+ class TruffleRubySet < ::Set
51
+ end
52
+
53
+ ThreadSafe::Util.make_synchronized_on_truffleruby Concurrent::TruffleRubySet
54
+ TruffleRubySet
55
+
56
+ else
57
+ warn 'Possibly unsupported Ruby implementation'
58
+ ::Set
59
+ end
60
+ private_constant :SetImplementation
61
+
62
+ # @!macro concurrent_set
63
+ class Set < SetImplementation
64
+ end
65
+ end
66
+
@@ -0,0 +1,129 @@
1
+ require 'concurrent/synchronization/abstract_struct'
2
+ require 'concurrent/errors'
3
+ require 'concurrent/synchronization'
4
+
5
+ module Concurrent
6
+
7
+ # An thread-safe, write-once variation of Ruby's standard `Struct`.
8
+ # Each member can have its value set at most once, either at construction
9
+ # or any time thereafter. Attempting to assign a value to a member
10
+ # that has already been set will result in a `Concurrent::ImmutabilityError`.
11
+ #
12
+ # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct`
13
+ # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword
14
+ module SettableStruct
15
+ include Synchronization::AbstractStruct
16
+
17
+ # @!macro struct_values
18
+ def values
19
+ synchronize { ns_values }
20
+ end
21
+ alias_method :to_a, :values
22
+
23
+ # @!macro struct_values_at
24
+ def values_at(*indexes)
25
+ synchronize { ns_values_at(indexes) }
26
+ end
27
+
28
+ # @!macro struct_inspect
29
+ def inspect
30
+ synchronize { ns_inspect }
31
+ end
32
+ alias_method :to_s, :inspect
33
+
34
+ # @!macro struct_merge
35
+ def merge(other, &block)
36
+ synchronize { ns_merge(other, &block) }
37
+ end
38
+
39
+ # @!macro struct_to_h
40
+ def to_h
41
+ synchronize { ns_to_h }
42
+ end
43
+
44
+ # @!macro struct_get
45
+ def [](member)
46
+ synchronize { ns_get(member) }
47
+ end
48
+
49
+ # @!macro struct_equality
50
+ def ==(other)
51
+ synchronize { ns_equality(other) }
52
+ end
53
+
54
+ # @!macro struct_each
55
+ def each(&block)
56
+ return enum_for(:each) unless block_given?
57
+ synchronize { ns_each(&block) }
58
+ end
59
+
60
+ # @!macro struct_each_pair
61
+ def each_pair(&block)
62
+ return enum_for(:each_pair) unless block_given?
63
+ synchronize { ns_each_pair(&block) }
64
+ end
65
+
66
+ # @!macro struct_select
67
+ def select(&block)
68
+ return enum_for(:select) unless block_given?
69
+ synchronize { ns_select(&block) }
70
+ end
71
+
72
+ # @!macro struct_set
73
+ #
74
+ # @raise [Concurrent::ImmutabilityError] if the given member has already been set
75
+ def []=(member, value)
76
+ if member.is_a? Integer
77
+ length = synchronize { @values.length }
78
+ if member >= length
79
+ raise IndexError.new("offset #{member} too large for struct(size:#{length})")
80
+ end
81
+ synchronize do
82
+ unless @values[member].nil?
83
+ raise Concurrent::ImmutabilityError.new('struct member has already been set')
84
+ end
85
+ @values[member] = value
86
+ end
87
+ else
88
+ send("#{member}=", value)
89
+ end
90
+ rescue NoMethodError
91
+ raise NameError.new("no member '#{member}' in struct")
92
+ end
93
+
94
+ # @!macro struct_new
95
+ def self.new(*args, &block)
96
+ clazz_name = nil
97
+ if args.length == 0
98
+ raise ArgumentError.new('wrong number of arguments (0 for 1+)')
99
+ elsif args.length > 0 && args.first.is_a?(String)
100
+ clazz_name = args.shift
101
+ end
102
+ FACTORY.define_struct(clazz_name, args, &block)
103
+ end
104
+
105
+ FACTORY = Class.new(Synchronization::LockableObject) do
106
+ def define_struct(name, members, &block)
107
+ synchronize do
108
+ clazz = Synchronization::AbstractStruct.define_struct_class(SettableStruct, Synchronization::LockableObject, name, members, &block)
109
+ members.each_with_index do |member, index|
110
+ clazz.send :remove_method, member if clazz.instance_methods.include? member
111
+ clazz.send(:define_method, member) do
112
+ synchronize { @values[index] }
113
+ end
114
+ clazz.send(:define_method, "#{member}=") do |value|
115
+ synchronize do
116
+ unless @values[index].nil?
117
+ raise Concurrent::ImmutabilityError.new('struct member has already been set')
118
+ end
119
+ @values[index] = value
120
+ end
121
+ end
122
+ end
123
+ clazz
124
+ end
125
+ end
126
+ end.new
127
+ private_constant :FACTORY
128
+ end
129
+ end