concurrent-ruby 0.8.0.pre2-java → 0.9.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +114 -3
- data/README.md +111 -55
- data/lib/concurrent.rb +90 -14
- data/lib/concurrent/async.rb +143 -51
- data/lib/concurrent/atom.rb +131 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
- data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
- data/lib/concurrent/atomic/atomic_reference.rb +49 -0
- data/lib/concurrent/atomic/condition.rb +23 -12
- data/lib/concurrent/atomic/count_down_latch.rb +23 -21
- data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
- data/lib/concurrent/atomic/event.rb +33 -42
- data/lib/concurrent/atomic/read_write_lock.rb +252 -0
- data/lib/concurrent/atomic/semaphore.rb +64 -89
- data/lib/concurrent/atomic/thread_local_var.rb +130 -58
- data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +34 -3
- data/lib/concurrent/atomic_reference/jruby.rb +6 -3
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +17 -39
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
- data/lib/concurrent/atomic_reference/rbx.rb +4 -1
- data/lib/concurrent/atomic_reference/ruby.rb +6 -3
- data/lib/concurrent/atomics.rb +74 -4
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
- data/lib/concurrent/collection/priority_queue.rb +300 -245
- data/lib/concurrent/concern/deprecation.rb +34 -0
- data/lib/concurrent/concern/dereferenceable.rb +88 -0
- data/lib/concurrent/concern/logging.rb +27 -0
- data/lib/concurrent/concern/obligation.rb +228 -0
- data/lib/concurrent/concern/observable.rb +85 -0
- data/lib/concurrent/configuration.rb +234 -109
- data/lib/concurrent/dataflow.rb +2 -3
- data/lib/concurrent/delay.rb +141 -50
- data/lib/concurrent/edge.rb +30 -0
- data/lib/concurrent/errors.rb +19 -7
- data/lib/concurrent/exchanger.rb +25 -1
- data/lib/concurrent/executor/cached_thread_pool.rb +51 -33
- data/lib/concurrent/executor/executor.rb +46 -299
- data/lib/concurrent/executor/executor_service.rb +521 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +196 -23
- data/lib/concurrent/executor/immediate_executor.rb +9 -9
- data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
- data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
- data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
- data/lib/concurrent/executor/safe_task_executor.rb +5 -4
- data/lib/concurrent/executor/serialized_execution.rb +22 -18
- data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
- data/lib/concurrent/executor/single_thread_executor.rb +32 -21
- data/lib/concurrent/executor/thread_pool_executor.rb +73 -60
- data/lib/concurrent/executor/timer_set.rb +96 -84
- data/lib/concurrent/executors.rb +1 -1
- data/lib/concurrent/future.rb +71 -38
- data/lib/concurrent/immutable_struct.rb +89 -0
- data/lib/concurrent/ivar.rb +152 -60
- data/lib/concurrent/lazy_register.rb +40 -20
- data/lib/concurrent/maybe.rb +226 -0
- data/lib/concurrent/mutable_struct.rb +227 -0
- data/lib/concurrent/mvar.rb +44 -43
- data/lib/concurrent/promise.rb +229 -136
- data/lib/concurrent/scheduled_task.rb +341 -43
- data/lib/concurrent/settable_struct.rb +127 -0
- data/lib/concurrent/synchronization.rb +17 -0
- data/lib/concurrent/synchronization/abstract_object.rb +163 -0
- data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
- data/lib/concurrent/synchronization/condition.rb +53 -0
- data/lib/concurrent/synchronization/java_object.rb +34 -0
- data/lib/concurrent/synchronization/lock.rb +32 -0
- data/lib/concurrent/synchronization/monitor_object.rb +26 -0
- data/lib/concurrent/synchronization/mutex_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +78 -0
- data/lib/concurrent/synchronization/rbx_object.rb +75 -0
- data/lib/concurrent/timer_task.rb +92 -103
- data/lib/concurrent/tvar.rb +42 -38
- data/lib/concurrent/utilities.rb +3 -1
- data/lib/concurrent/utility/at_exit.rb +97 -0
- data/lib/concurrent/utility/engine.rb +44 -0
- data/lib/concurrent/utility/monotonic_time.rb +59 -0
- data/lib/concurrent/utility/native_extension_loader.rb +56 -0
- data/lib/concurrent/utility/processor_counter.rb +156 -0
- data/lib/concurrent/utility/timeout.rb +18 -14
- data/lib/concurrent/utility/timer.rb +11 -6
- data/lib/concurrent/version.rb +2 -1
- data/lib/concurrent_ruby.rb +1 -0
- data/lib/concurrent_ruby_ext.jar +0 -0
- metadata +46 -66
- data/lib/concurrent/actor.rb +0 -103
- data/lib/concurrent/actor/behaviour.rb +0 -70
- data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
- data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
- data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
- data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
- data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
- data/lib/concurrent/actor/behaviour/linking.rb +0 -45
- data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
- data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
- data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
- data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
- data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
- data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
- data/lib/concurrent/actor/behaviour/termination.rb +0 -54
- data/lib/concurrent/actor/context.rb +0 -154
- data/lib/concurrent/actor/core.rb +0 -217
- data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
- data/lib/concurrent/actor/envelope.rb +0 -41
- data/lib/concurrent/actor/errors.rb +0 -27
- data/lib/concurrent/actor/internal_delegations.rb +0 -49
- data/lib/concurrent/actor/public_delegations.rb +0 -40
- data/lib/concurrent/actor/reference.rb +0 -81
- data/lib/concurrent/actor/root.rb +0 -37
- data/lib/concurrent/actor/type_check.rb +0 -48
- data/lib/concurrent/actor/utils.rb +0 -10
- data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
- data/lib/concurrent/actor/utils/balancer.rb +0 -42
- data/lib/concurrent/actor/utils/broadcast.rb +0 -52
- data/lib/concurrent/actor/utils/pool.rb +0 -59
- data/lib/concurrent/actress.rb +0 -3
- data/lib/concurrent/agent.rb +0 -209
- data/lib/concurrent/atomic.rb +0 -92
- data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
- data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
- data/lib/concurrent/atomic/synchronization.rb +0 -51
- data/lib/concurrent/channel/buffered_channel.rb +0 -85
- data/lib/concurrent/channel/channel.rb +0 -41
- data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
- data/lib/concurrent/channel/waitable_list.rb +0 -40
- data/lib/concurrent/channels.rb +0 -5
- data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
- data/lib/concurrent/collection/ring_buffer.rb +0 -59
- data/lib/concurrent/collections.rb +0 -3
- data/lib/concurrent/dereferenceable.rb +0 -108
- data/lib/concurrent/executor/java_cached_thread_pool.rb +0 -32
- data/lib/concurrent/executor/java_fixed_thread_pool.rb +0 -31
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +0 -29
- data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +0 -32
- data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
- data/lib/concurrent/logging.rb +0 -20
- data/lib/concurrent/obligation.rb +0 -171
- data/lib/concurrent/observable.rb +0 -73
- data/lib/concurrent/options_parser.rb +0 -48
- data/lib/concurrent/utility/processor_count.rb +0 -152
- data/lib/extension_helper.rb +0 -37
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
module Synchronization
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
# @!macro internal_implementation_note
|
8
|
+
class MonitorObject < MutexObject
|
9
|
+
def initialize
|
10
|
+
@__lock__ = ::Monitor.new
|
11
|
+
@__condition__ = @__lock__.new_cond
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def synchronize
|
17
|
+
@__lock__.synchronize { yield }
|
18
|
+
end
|
19
|
+
|
20
|
+
def ns_wait(timeout = nil)
|
21
|
+
@__condition__.wait timeout
|
22
|
+
self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Concurrent
|
2
|
+
module Synchronization
|
3
|
+
|
4
|
+
# @!visibility private
|
5
|
+
# @!macro internal_implementation_note
|
6
|
+
class MutexObject < AbstractObject
|
7
|
+
def initialize
|
8
|
+
@__lock__ = ::Mutex.new
|
9
|
+
@__condition__ = ::ConditionVariable.new
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def synchronize
|
15
|
+
if @__lock__.owned?
|
16
|
+
yield
|
17
|
+
else
|
18
|
+
@__lock__.synchronize { yield }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def ns_signal
|
23
|
+
@__condition__.signal
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def ns_broadcast
|
28
|
+
@__condition__.broadcast
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def ns_wait(timeout = nil)
|
33
|
+
@__condition__.wait @__lock__, timeout
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def ensure_ivar_visibility!
|
38
|
+
# relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars
|
39
|
+
# https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Concurrent
|
2
|
+
module Synchronization
|
3
|
+
|
4
|
+
# @!visibility private
|
5
|
+
# @!macro internal_implementation_note
|
6
|
+
Implementation = case
|
7
|
+
when Concurrent.on_jruby?
|
8
|
+
JavaObject
|
9
|
+
when Concurrent.on_cruby? && Concurrent.ruby_version(:<=, 1, 9, 3)
|
10
|
+
MonitorObject
|
11
|
+
when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3)
|
12
|
+
MutexObject
|
13
|
+
when Concurrent.on_rbx?
|
14
|
+
RbxObject
|
15
|
+
else
|
16
|
+
warn 'Possibly unsupported Ruby implementation'
|
17
|
+
MutexObject
|
18
|
+
end
|
19
|
+
private_constant :Implementation
|
20
|
+
|
21
|
+
# @!macro [attach] synchronization_object
|
22
|
+
#
|
23
|
+
# Safe synchronization under any Ruby implementation.
|
24
|
+
# It provides methods like {#synchronize}, {#wait}, {#signal} and {#broadcast}.
|
25
|
+
# Provides a single layer which can improve its implementation over time without changes needed to
|
26
|
+
# the classes using it. Use {Synchronization::Object} not this abstract class.
|
27
|
+
#
|
28
|
+
# @note this object does not support usage together with
|
29
|
+
# [`Thread#wakeup`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-wakeup)
|
30
|
+
# and [`Thread#raise`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-raise).
|
31
|
+
# `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and
|
32
|
+
# `Thread#wakeup` will not work on all platforms.
|
33
|
+
#
|
34
|
+
# @see {Event} implementation as an example of this class use
|
35
|
+
#
|
36
|
+
# @example simple
|
37
|
+
# class AnClass < Synchronization::Object
|
38
|
+
# def initialize
|
39
|
+
# super
|
40
|
+
# synchronize { @value = 'asd' }
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# def value
|
44
|
+
# synchronize { @value }
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
class Object < Implementation
|
49
|
+
|
50
|
+
# @!method initialize(*args, &block)
|
51
|
+
# @!macro synchronization_object_method_initialize
|
52
|
+
|
53
|
+
# @!method synchronize
|
54
|
+
# @!macro synchronization_object_method_synchronize
|
55
|
+
|
56
|
+
# @!method initialize(*args, &block)
|
57
|
+
# @!macro synchronization_object_method_ns_initialize
|
58
|
+
|
59
|
+
# @!method wait_until(timeout = nil, &condition)
|
60
|
+
# @!macro synchronization_object_method_ns_wait_until
|
61
|
+
|
62
|
+
# @!method wait(timeout = nil)
|
63
|
+
# @!macro synchronization_object_method_ns_wait
|
64
|
+
|
65
|
+
# @!method signal
|
66
|
+
# @!macro synchronization_object_method_ns_signal
|
67
|
+
|
68
|
+
# @!method broadcast
|
69
|
+
# @!macro synchronization_object_method_ns_broadcast
|
70
|
+
|
71
|
+
# @!method ensure_ivar_visibility!
|
72
|
+
# @!macro synchronization_object_method_ensure_ivar_visibility
|
73
|
+
|
74
|
+
# @!method self.attr_volatile(*names)
|
75
|
+
# @!macro synchronization_object_method_self_attr_volatile
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Concurrent
|
2
|
+
module Synchronization
|
3
|
+
|
4
|
+
if Concurrent.on_rbx?
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
# @!macro internal_implementation_note
|
8
|
+
class RbxObject < AbstractObject
|
9
|
+
def initialize
|
10
|
+
@Waiters = []
|
11
|
+
ensure_ivar_visibility!
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def synchronize(&block)
|
17
|
+
Rubinius.synchronize(self, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def ns_wait(timeout = nil)
|
21
|
+
wchan = Rubinius::Channel.new
|
22
|
+
|
23
|
+
begin
|
24
|
+
@Waiters.push wchan
|
25
|
+
Rubinius.unlock(self)
|
26
|
+
signaled = wchan.receive_timeout timeout
|
27
|
+
ensure
|
28
|
+
Rubinius.lock(self)
|
29
|
+
|
30
|
+
if !signaled && !@Waiters.delete(wchan)
|
31
|
+
# we timed out, but got signaled afterwards,
|
32
|
+
# so pass that signal on to the next waiter
|
33
|
+
@Waiters.shift << true unless @Waiters.empty?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def ns_signal
|
41
|
+
@Waiters.shift << true unless @Waiters.empty?
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def ns_broadcast
|
46
|
+
@Waiters.shift << true until @Waiters.empty?
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def ensure_ivar_visibility!
|
51
|
+
# Rubinius instance variables are not volatile so we need to insert barrier
|
52
|
+
Rubinius.memory_barrier
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.attr_volatile *names
|
56
|
+
names.each do |name|
|
57
|
+
ivar = :"@volatile_#{name}"
|
58
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
59
|
+
def #{name}
|
60
|
+
Rubinius.memory_barrier
|
61
|
+
#{ivar}
|
62
|
+
end
|
63
|
+
|
64
|
+
def #{name}=(value)
|
65
|
+
#{ivar} = value
|
66
|
+
Rubinius.memory_barrier
|
67
|
+
end
|
68
|
+
RUBY
|
69
|
+
end
|
70
|
+
names.map { |n| [n, :"#{n}="] }.flatten
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -1,72 +1,81 @@
|
|
1
|
-
require 'concurrent/
|
2
|
-
require 'concurrent/
|
1
|
+
require 'concurrent/collection/copy_on_notify_observer_set'
|
2
|
+
require 'concurrent/concern/dereferenceable'
|
3
|
+
require 'concurrent/concern/observable'
|
3
4
|
require 'concurrent/atomic/atomic_boolean'
|
4
|
-
require 'concurrent/executor/
|
5
|
+
require 'concurrent/executor/executor_service'
|
5
6
|
require 'concurrent/executor/safe_task_executor'
|
6
7
|
|
7
8
|
module Concurrent
|
8
9
|
|
9
|
-
# A very common currency pattern is to run a thread that performs a task at
|
10
|
-
# intervals. The thread that performs the task sleeps for the given
|
11
|
-
# wakes up and performs the task. Lather, rinse, repeat... This
|
12
|
-
# problems. First, it is difficult to test the business
|
13
|
-
# task itself is tightly coupled with the
|
14
|
-
# raised while performing the task can
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
10
|
+
# A very common currency pattern is to run a thread that performs a task at
|
11
|
+
# regular intervals. The thread that performs the task sleeps for the given
|
12
|
+
# interval then wakes up and performs the task. Lather, rinse, repeat... This
|
13
|
+
# pattern causes two problems. First, it is difficult to test the business
|
14
|
+
# logic of the task because the task itself is tightly coupled with the
|
15
|
+
# concurrency logic. Second, an exception raised while performing the task can
|
16
|
+
# cause the entire thread to abend. In a long-running application where the
|
17
|
+
# task thread is intended to run for days/weeks/years a crashed task thread
|
18
|
+
# can pose a significant problem. `TimerTask` alleviates both problems.
|
19
|
+
#
|
20
|
+
# When a `TimerTask` is launched it starts a thread for monitoring the
|
21
|
+
# execution interval. The `TimerTask` thread does not perform the task,
|
22
|
+
# however. Instead, the TimerTask launches the task on a separate thread.
|
23
|
+
# Should the task experience an unrecoverable crash only the task thread will
|
24
|
+
# crash. This makes the `TimerTask` very fault tolerant Additionally, the
|
25
|
+
# `TimerTask` thread can respond to the success or failure of the task,
|
26
|
+
# performing logging or ancillary operations. `TimerTask` can also be
|
27
|
+
# configured with a timeout value allowing it to kill a task that runs too
|
28
|
+
# long.
|
29
|
+
#
|
30
|
+
# One other advantage of `TimerTask` is that it forces the business logic to
|
31
|
+
# be completely decoupled from the concurrency logic. The business logic can
|
32
|
+
# be tested separately then passed to the `TimerTask` for scheduling and
|
33
|
+
# running.
|
34
|
+
#
|
35
|
+
# In some cases it may be necessary for a `TimerTask` to affect its own
|
36
|
+
# execution cycle. To facilitate this, a reference to the TimerTask instance
|
37
|
+
# is passed as an argument to the provided block every time the task is
|
38
|
+
# executed.
|
39
|
+
#
|
40
|
+
# The `TimerTask` class includes the `Dereferenceable` mixin module so the
|
41
|
+
# result of the last execution is always available via the `#value` method.
|
42
|
+
# Derefencing options can be passed to the `TimerTask` during construction or
|
43
|
+
# at any later time using the `#set_deref_options` method.
|
44
|
+
#
|
39
45
|
# `TimerTask` supports notification through the Ruby standard library
|
40
|
-
# {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
|
41
|
-
# module. On execution the `TimerTask` will notify the observers
|
42
|
-
# with three arguments: time of execution, the result of the block (or nil on
|
43
|
-
# and any raised exceptions (or nil on success). If the timeout
|
44
|
-
# the observer will receive a `Concurrent::TimeoutError`
|
46
|
+
# {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
|
47
|
+
# Observable} module. On execution the `TimerTask` will notify the observers
|
48
|
+
# with three arguments: time of execution, the result of the block (or nil on
|
49
|
+
# failure), and any raised exceptions (or nil on success). If the timeout
|
50
|
+
# interval is exceeded the observer will receive a `Concurrent::TimeoutError`
|
51
|
+
# object as the third argument.
|
52
|
+
#
|
53
|
+
# @!macro copy_options
|
45
54
|
#
|
46
55
|
# @example Basic usage
|
47
56
|
# task = Concurrent::TimerTask.new{ puts 'Boom!' }
|
48
57
|
# task.execute
|
49
|
-
#
|
58
|
+
#
|
50
59
|
# task.execution_interval #=> 60 (default)
|
51
60
|
# task.timeout_interval #=> 30 (default)
|
52
|
-
#
|
61
|
+
#
|
53
62
|
# # wait 60 seconds...
|
54
63
|
# #=> 'Boom!'
|
55
|
-
#
|
64
|
+
#
|
56
65
|
# task.shutdown #=> true
|
57
66
|
#
|
58
67
|
# @example Configuring `:execution_interval` and `:timeout_interval`
|
59
68
|
# task = Concurrent::TimerTask.new(execution_interval: 5, timeout_interval: 5) do
|
60
69
|
# puts 'Boom!'
|
61
70
|
# end
|
62
|
-
#
|
71
|
+
#
|
63
72
|
# task.execution_interval #=> 5
|
64
73
|
# task.timeout_interval #=> 5
|
65
74
|
#
|
66
75
|
# @example Immediate execution with `:run_now`
|
67
76
|
# task = Concurrent::TimerTask.new(run_now: true){ puts 'Boom!' }
|
68
77
|
# task.execute
|
69
|
-
#
|
78
|
+
#
|
70
79
|
# #=> 'Boom!'
|
71
80
|
#
|
72
81
|
# @example Last `#value` and `Dereferenceable` mixin
|
@@ -74,7 +83,7 @@ module Concurrent
|
|
74
83
|
# dup_on_deref: true,
|
75
84
|
# execution_interval: 5
|
76
85
|
# ){ Time.now }
|
77
|
-
#
|
86
|
+
#
|
78
87
|
# task.execute
|
79
88
|
# Time.now #=> 2013-11-07 18:06:50 -0500
|
80
89
|
# sleep(10)
|
@@ -90,7 +99,7 @@ module Concurrent
|
|
90
99
|
# task.shutdown
|
91
100
|
# end
|
92
101
|
# end
|
93
|
-
#
|
102
|
+
#
|
94
103
|
# timer_task.execute # blocking call - this task will stop itself
|
95
104
|
# #=> Boom!
|
96
105
|
# #=> Boom! Boom!
|
@@ -111,29 +120,29 @@ module Concurrent
|
|
111
120
|
# end
|
112
121
|
# end
|
113
122
|
# end
|
114
|
-
#
|
123
|
+
#
|
115
124
|
# task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ 42 }
|
116
125
|
# task.add_observer(TaskObserver.new)
|
117
126
|
# task.execute
|
118
|
-
#
|
127
|
+
#
|
119
128
|
# #=> (2013-10-13 19:08:58 -0400) Execution successfully returned 42
|
120
129
|
# #=> (2013-10-13 19:08:59 -0400) Execution successfully returned 42
|
121
130
|
# #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42
|
122
131
|
# task.shutdown
|
123
|
-
#
|
132
|
+
#
|
124
133
|
# task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ sleep }
|
125
134
|
# task.add_observer(TaskObserver.new)
|
126
135
|
# task.execute
|
127
|
-
#
|
136
|
+
#
|
128
137
|
# #=> (2013-10-13 19:07:25 -0400) Execution timed out
|
129
138
|
# #=> (2013-10-13 19:07:27 -0400) Execution timed out
|
130
139
|
# #=> (2013-10-13 19:07:29 -0400) Execution timed out
|
131
140
|
# task.shutdown
|
132
|
-
#
|
141
|
+
#
|
133
142
|
# task = Concurrent::TimerTask.new(execution_interval: 1){ raise StandardError }
|
134
143
|
# task.add_observer(TaskObserver.new)
|
135
144
|
# task.execute
|
136
|
-
#
|
145
|
+
#
|
137
146
|
# #=> (2013-10-13 19:09:37 -0400) Execution failed with error StandardError
|
138
147
|
# #=> (2013-10-13 19:09:38 -0400) Execution failed with error StandardError
|
139
148
|
# #=> (2013-10-13 19:09:39 -0400) Execution failed with error StandardError
|
@@ -141,10 +150,9 @@ module Concurrent
|
|
141
150
|
#
|
142
151
|
# @see http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
|
143
152
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
|
144
|
-
class TimerTask
|
145
|
-
include Dereferenceable
|
146
|
-
include
|
147
|
-
include Concurrent::Observable
|
153
|
+
class TimerTask < RubyExecutorService
|
154
|
+
include Concern::Dereferenceable
|
155
|
+
include Concern::Observable
|
148
156
|
|
149
157
|
# Default `:execution_interval` in seconds.
|
150
158
|
EXECUTION_INTERVAL = 60
|
@@ -163,36 +171,22 @@ module Concurrent
|
|
163
171
|
# @option opts [Boolean] :run_now Whether to run the task immediately
|
164
172
|
# upon instantiation or to wait until the first # execution_interval
|
165
173
|
# has passed (default: false)
|
166
|
-
#
|
174
|
+
#
|
175
|
+
# @!macro deref_options
|
176
|
+
#
|
167
177
|
# @raise ArgumentError when no block is given.
|
168
|
-
#
|
178
|
+
#
|
169
179
|
# @yield to the block after :execution_interval seconds have passed since
|
170
180
|
# the last yield
|
171
181
|
# @yieldparam task a reference to the `TimerTask` instance so that the
|
172
182
|
# block can control its own lifecycle. Necessary since `self` will
|
173
183
|
# refer to the execution context of the block rather than the running
|
174
184
|
# `TimerTask`.
|
175
|
-
#
|
176
|
-
# @note Calls Concurrent::Dereferenceable# set_deref_options passing `opts`.
|
177
|
-
# All options supported by Concurrent::Dereferenceable can be set
|
178
|
-
# during object initialization.
|
179
185
|
#
|
180
186
|
# @return [TimerTask] the new `TimerTask`
|
181
|
-
#
|
182
|
-
# @see Concurrent::Dereferenceable# set_deref_options
|
183
187
|
def initialize(opts = {}, &task)
|
184
188
|
raise ArgumentError.new('no block given') unless block_given?
|
185
|
-
|
186
|
-
init_executor
|
187
|
-
set_deref_options(opts)
|
188
|
-
|
189
|
-
self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
|
190
|
-
self.timeout_interval = opts[:timeout] || opts[:timeout_interval] || TIMEOUT_INTERVAL
|
191
|
-
@run_now = opts[:now] || opts[:run_now]
|
192
|
-
@executor = Concurrent::SafeTaskExecutor.new(task)
|
193
|
-
@running = Concurrent::AtomicBoolean.new(false)
|
194
|
-
|
195
|
-
self.observers = CopyOnNotifyObserverSet.new
|
189
|
+
super
|
196
190
|
end
|
197
191
|
|
198
192
|
# Is the executor running?
|
@@ -215,10 +209,8 @@ module Concurrent
|
|
215
209
|
# @example Instance and execute in one line
|
216
210
|
# task = Concurrent::TimerTask.new(execution_interval: 10){ print "Hello World\n" }.execute
|
217
211
|
# task.running? #=> true
|
218
|
-
#
|
219
|
-
# @since 0.6.0
|
220
212
|
def execute
|
221
|
-
|
213
|
+
synchronize do
|
222
214
|
if @running.false?
|
223
215
|
@running.make_true
|
224
216
|
schedule_next_task(@run_now ? 0 : @execution_interval)
|
@@ -231,11 +223,9 @@ module Concurrent
|
|
231
223
|
#
|
232
224
|
# @!macro timer_task_initialize
|
233
225
|
#
|
234
|
-
# @example
|
226
|
+
# @example
|
235
227
|
# task = Concurrent::TimerTask.execute(execution_interval: 10){ print "Hello World\n" }
|
236
228
|
# task.running? #=> true
|
237
|
-
#
|
238
|
-
# @since 0.6.0
|
239
229
|
def self.execute(opts = {}, &task)
|
240
230
|
TimerTask.new(opts, &task).execute
|
241
231
|
end
|
@@ -244,10 +234,7 @@ module Concurrent
|
|
244
234
|
# @return [Fixnum] Number of seconds after the task completes before the
|
245
235
|
# task is performed again.
|
246
236
|
def execution_interval
|
247
|
-
|
248
|
-
@execution_interval
|
249
|
-
ensure
|
250
|
-
mutex.unlock
|
237
|
+
synchronize { @execution_interval }
|
251
238
|
end
|
252
239
|
|
253
240
|
# @!attribute [rw] execution_interval
|
@@ -257,12 +244,7 @@ module Concurrent
|
|
257
244
|
if (value = value.to_f) <= 0.0
|
258
245
|
raise ArgumentError.new('must be greater than zero')
|
259
246
|
else
|
260
|
-
|
261
|
-
mutex.lock
|
262
|
-
@execution_interval = value
|
263
|
-
ensure
|
264
|
-
mutex.unlock
|
265
|
-
end
|
247
|
+
synchronize { @execution_interval = value }
|
266
248
|
end
|
267
249
|
end
|
268
250
|
|
@@ -270,10 +252,7 @@ module Concurrent
|
|
270
252
|
# @return [Fixnum] Number of seconds the task can run before it is
|
271
253
|
# considered to have failed.
|
272
254
|
def timeout_interval
|
273
|
-
|
274
|
-
@timeout_interval
|
275
|
-
ensure
|
276
|
-
mutex.unlock
|
255
|
+
synchronize { @timeout_interval }
|
277
256
|
end
|
278
257
|
|
279
258
|
# @!attribute [rw] timeout_interval
|
@@ -283,12 +262,7 @@ module Concurrent
|
|
283
262
|
if (value = value.to_f) <= 0.0
|
284
263
|
raise ArgumentError.new('must be greater than zero')
|
285
264
|
else
|
286
|
-
|
287
|
-
mutex.lock
|
288
|
-
@timeout_interval = value
|
289
|
-
ensure
|
290
|
-
mutex.unlock
|
291
|
-
end
|
265
|
+
synchronize { @timeout_interval = value }
|
292
266
|
end
|
293
267
|
end
|
294
268
|
|
@@ -296,6 +270,19 @@ module Concurrent
|
|
296
270
|
|
297
271
|
protected
|
298
272
|
|
273
|
+
def ns_initialize(opts, &task)
|
274
|
+
init_mutex(self)
|
275
|
+
set_deref_options(opts)
|
276
|
+
|
277
|
+
self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
|
278
|
+
self.timeout_interval = opts[:timeout] || opts[:timeout_interval] || TIMEOUT_INTERVAL
|
279
|
+
@run_now = opts[:now] || opts[:run_now]
|
280
|
+
@executor = Concurrent::SafeTaskExecutor.new(task)
|
281
|
+
@running = Concurrent::AtomicBoolean.new(false)
|
282
|
+
|
283
|
+
self.observers = Collection::CopyOnNotifyObserverSet.new
|
284
|
+
end
|
285
|
+
|
299
286
|
# @!visibility private
|
300
287
|
def shutdown_execution
|
301
288
|
@running.make_false
|
@@ -310,13 +297,14 @@ module Concurrent
|
|
310
297
|
|
311
298
|
# @!visibility private
|
312
299
|
def schedule_next_task(interval = execution_interval)
|
313
|
-
|
300
|
+
ScheduledTask.execute(interval, args: [Concurrent::Event.new], &method(:execute_task))
|
301
|
+
nil
|
314
302
|
end
|
315
303
|
|
316
304
|
# @!visibility private
|
317
305
|
def execute_task(completion)
|
318
|
-
return unless @running.true?
|
319
|
-
|
306
|
+
return nil unless @running.true?
|
307
|
+
ScheduledTask.execute(execution_interval, args: [completion], &method(:timeout_task))
|
320
308
|
_success, value, reason = @executor.execute(self)
|
321
309
|
if completion.try?
|
322
310
|
self.value = value
|
@@ -326,6 +314,7 @@ module Concurrent
|
|
326
314
|
[time, self.value, reason]
|
327
315
|
end
|
328
316
|
end
|
317
|
+
nil
|
329
318
|
end
|
330
319
|
|
331
320
|
# @!visibility private
|