@@ -16,19 +16,14 @@ module Concurrent
16
16
# @!macro monotonic_clock_warning
17
17
class TimerSet < RubyExecutorService
18
18
19
- # A class for encapsulating a task and its intended execution time.
20
- # It facilitates proper prioritization by overriding the comparison
21
- # (spaceship) operator as a comparison of the intended execution
22
- # times.
23
- #
24
- # @!visibility private
19
+ # An `IVar` representing a tasked queued for execution in a `TimerSet`.
25
20
class Task < Concurrent ::IVar
26
21
include Comparable
27
22
28
- # @!visibility private
29
- def initialize ( time , args , task )
23
+ def initialize ( parent , time , args , task )
30
24
super ( )
31
25
synchronize do
26
+ @parent = parent
32
27
@time = time
33
28
@args = args
34
29
@task = task
@@ -40,20 +35,20 @@ def time
40
35
synchronize { @time }
41
36
end
42
37
43
- # @!visibility private
44
38
def <=>( other )
45
39
self . time <=> other . time
46
40
end
47
41
48
- # @!visibility private
49
42
def cancelled?
50
43
state == :cancelled
51
44
end
52
45
53
- # @!visibility private
54
46
def cancel
55
47
if compare_and_set_state ( :cancelled , :pending )
56
48
complete ( false , nil , CancelledOperationError . new )
49
+ # To avoid deadlocks this call must occur outside of #synchronize
50
+ # Changing the state above should prevent redundant calls
51
+ @parent . send ( :remove_task , self )
57
52
true
58
53
else
59
54
false
@@ -64,8 +59,9 @@ def cancel
64
59
def execute
65
60
safe_execute ( @task , @args )
66
61
end
62
+
63
+ protected :set , :try_set
67
64
end
68
- private_constant :Task
69
65
70
66
# Create a new set of timed tasks.
71
67
#
@@ -88,7 +84,8 @@ def initialize(opts = {})
88
84
#
89
85
# @yield the task to be performed
90
86
#
91
- # @return [Boolean] true if the message is post, false after shutdown
87
+ # @return [Concurrent::TimerSet::Task, false] IVar representing the task if the post
88
+ # is successful; false after shutdown
92
89
#
93
90
# @raise [ArgumentError] if the intended execution time is not in the future
94
91
# @raise [ArgumentError] if no block is given
@@ -102,7 +99,7 @@ def post(delay, *args, &task)
102
99
return false unless running?
103
100
104
101
time = Concurrent . monotonic_time + delay
105
- task = Task . new ( time , args , task )
102
+ task = Task . new ( self , time , args , task )
106
103
107
104
if ( delay ) <= 0.01
108
105
@task_executor . post { task . execute }
@@ -152,6 +149,18 @@ def self.calculate_delay!(delay)
152
149
153
150
protected
154
151
152
+ # Remove the given task from the queue.
153
+ #
154
+ # @note This is intended as a callback method from Task only.
155
+ # It is not intended to be used directly. Cancel a task by
156
+ # using the `Task#cancel` method.
157
+ #
158
+ # @!visibility private
159
+ def remove_task ( task )
160
+ synchronize { @queue . delete ( task ) }
161
+ end
162
+
163
+ # @!visibility private
155
164
def ns_initialize ( opts )
156
165
@queue = PriorityQueue . new ( order : :min )
157
166
@task_executor = Executor . executor_from_options ( opts ) || Concurrent . global_io_executor
@@ -204,9 +213,9 @@ def process_tasks
204
213
205
214
private
206
215
216
+ # @!visibility private
207
217
def <<( task )
208
- post ( 0.0 , &task )
209
- self
218
+ raise NotImplementedError . new
210
219
end
211
220
end
212
221
end
0 commit comments