3
3
require 'concurrent/options_parser'
4
4
require 'concurrent/atomic/event'
5
5
require 'concurrent/collection/priority_queue'
6
+ require 'concurrent/executor/single_thread_executor'
6
7
7
8
module Concurrent
8
9
@@ -23,8 +24,8 @@ class TimerSet
23
24
# this executor rather than the global thread pool (overrides :operation)
24
25
def initialize ( opts = { } )
25
26
@queue = PriorityQueue . new ( order : :min )
26
- @executor = get_executor_from ( opts )
27
- @thread = nil
27
+ @task_executor = get_executor_from ( opts )
28
+ @timer_executor = SingleThreadExecutor . new
28
29
@condition = Condition . new
29
30
init_executor
30
31
end
@@ -50,10 +51,10 @@ def post(intended_time, *args, &task)
50
51
return false unless running?
51
52
52
53
if ( time - Time . now . to_f ) <= 0.01
53
- @executor . post ( *args , &task )
54
+ @task_executor . post ( *args , &task )
54
55
else
55
56
@queue . push ( Task . new ( time , args , task ) )
56
- check_processing_thread!
57
+ @timer_executor . post ( & method ( :process_tasks ) )
57
58
end
58
59
59
60
true
@@ -107,28 +108,10 @@ def <=>(other)
107
108
# @!visibility private
108
109
def shutdown_execution
109
110
@queue . clear
110
- @thread . kill if @thread
111
+ @timer_executor . kill
111
112
stopped_event . set
112
113
end
113
114
114
- # Check the status of the processing thread. This thread is responsible
115
- # for monitoring the internal task queue and sending tasks to the
116
- # executor when it is time for them to be processed. If there is no
117
- # processing thread one will be created. If the processing thread is
118
- # sleeping it will be woken up. If the processing thread has died it
119
- # will be garbage collected and a new one will be created.
120
- #
121
- # @!visibility private
122
- def check_processing_thread!
123
- return if shutdown? || @queue . empty?
124
-
125
- @thread ||= Thread . new do
126
- Thread . current . abort_on_exception = true
127
- process_tasks
128
- end
129
- end
130
-
131
-
132
115
# Run a loop and execute tasks in the scheduled order and at the approximate
133
116
# scheduled time. If no tasks remain the thread will exit gracefully so that
134
117
# garbage collection can occur. If there are no ready tasks it will sleep
@@ -137,19 +120,16 @@ def check_processing_thread!
137
120
# @!visibility private
138
121
def process_tasks
139
122
loop do
140
- mutex . synchronize do
141
- if @queue . empty?
142
- @thread = nil
143
- break
144
- end
123
+ break if @queue . empty?
145
124
146
- task = @queue . peek
147
- interval = task . time - Time . now . to_f
125
+ task = @queue . peek
126
+ interval = task . time - Time . now . to_f
148
127
149
- if interval <= 0
150
- @executor . post ( *task . args , &task . op )
151
- @queue . pop
152
- else
128
+ if interval <= 0
129
+ @task_executor . post ( *task . args , &task . op )
130
+ @queue . pop
131
+ else
132
+ mutex . synchronize do
153
133
@condition . wait ( mutex , [ interval , 60 ] . min )
154
134
end
155
135
end
0 commit comments