File tree Expand file tree Collapse file tree 2 files changed +62
-6
lines changed Expand file tree Collapse file tree 2 files changed +62
-6
lines changed Original file line number Diff line number Diff line change 1
1
require 'thread'
2
2
3
3
require 'concurrent/actor_ref'
4
+ require 'concurrent/event'
4
5
require 'concurrent/ivar'
5
6
6
7
module Concurrent
@@ -13,25 +14,25 @@ def initialize(actor, opts = {})
13
14
@mutex = Mutex . new
14
15
@queue = Queue . new
15
16
@thread = nil
16
- @stopped = false
17
+ @stop_event = Event . new
17
18
@abort_on_exception = opts . fetch ( :abort_on_exception , true )
18
19
@reset_on_error = opts . fetch ( :reset_on_error , true )
19
20
@exception_class = opts . fetch ( :rescue_exception , false ) ? Exception : StandardError
20
21
@observers = CopyOnNotifyObserverSet . new
21
22
end
22
23
23
24
def running?
24
- @mutex . synchronize { @stopped == false }
25
+ ! @stop_event . set?
25
26
end
26
27
27
28
def shutdown?
28
- @mutex . synchronize { @stopped == true }
29
+ @stop_event . set?
29
30
end
30
31
31
32
def post ( *msg , &block )
32
33
raise ArgumentError . new ( 'message cannot be empty' ) if msg . empty?
33
34
@mutex . synchronize do
34
- supervise unless @stopped == true
35
+ supervise unless shutdown?
35
36
end
36
37
ivar = IVar . new
37
38
@queue . push ( Message . new ( msg , ivar , block ) )
@@ -52,15 +53,19 @@ def post!(seconds, *msg)
52
53
53
54
def shutdown
54
55
@mutex . synchronize do
55
- return if @stopped
56
- @stopped = true
56
+ return if shutdown?
57
57
if @thread && @thread . alive?
58
58
@thread . kill
59
59
@actor . on_shutdown
60
60
end
61
+ @stop_event . set
61
62
end
62
63
end
63
64
65
+ def join ( timeout = nil )
66
+ @stop_event . wait ( timeout )
67
+ end
68
+
64
69
private
65
70
66
71
Message = Struct . new ( :payload , :ivar , :callback )
Original file line number Diff line number Diff line change @@ -169,6 +169,57 @@ def receive(*msg)
169
169
end
170
170
end
171
171
172
+ context '#join' do
173
+
174
+ it 'blocks until shutdown when no limit is given' do
175
+ start = Time . now
176
+ subject << :foo # start the actor's thread
177
+ Thread . new { sleep ( 1 ) ; subject . shutdown }
178
+ subject . join
179
+ stop = Time . now
180
+
181
+ subject . should be_shutdown
182
+ stop . should >= start + 1
183
+ stop . should <= start + 2
184
+ end
185
+
186
+ it 'blocks for no more than the given number of seconds' do
187
+ start = Time . now
188
+ subject << :foo # start the actor's thread
189
+ Thread . new { sleep ( 5 ) ; subject . shutdown }
190
+ subject . join ( 1 )
191
+ stop = Time . now
192
+
193
+ stop . should >= start + 1
194
+ stop . should <= start + 2
195
+ end
196
+
197
+ it 'returns true when shutdown has completed before timeout' do
198
+ subject << :foo # start the actor's thread
199
+ Thread . new { sleep ( 1 ) ; subject . shutdown }
200
+ subject . join . should be_true
201
+ end
202
+
203
+ it 'returns false on timeout' do
204
+ subject << :foo # start the actor's thread
205
+ Thread . new { sleep ( 5 ) ; subject . shutdown }
206
+ subject . join ( 1 ) . should be_false
207
+ end
208
+
209
+ it 'returns immediately when already shutdown' do
210
+ start = Time . now
211
+ subject << :foo # start the actor's thread
212
+ sleep ( 0.1 )
213
+ subject . shutdown
214
+ sleep ( 0.1 )
215
+
216
+ start = Time . now
217
+ subject . join
218
+ Time . now . should >= start
219
+ Time . now . should <= start + 0.1
220
+ end
221
+ end
222
+
172
223
context 'observation' do
173
224
174
225
let ( :observer_class ) do
You can’t perform that action at this time.
0 commit comments