thread 0.1.7 → 0.2.0
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/.travis.yml +2 -1
- data/README.md +2 -2
- data/lib/thread/channel.rb +6 -6
- data/lib/thread/every.rb +7 -7
- data/lib/thread/future.rb +8 -8
- data/lib/thread/pipe.rb +7 -7
- data/lib/thread/pool.rb +63 -62
- data/lib/thread/process.rb +7 -7
- data/lib/thread/promise.rb +3 -3
- data/spec/thread/pool_spec.rb +78 -0
- data/thread.gemspec +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f1ac6a92f77e49dec38a35d8f17c607568f2702
|
4
|
+
data.tar.gz: 794e057cc2b9ea319f1051e13d7d69f7f61a92dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8be737ccd11509f373d5a7c3d78a2e29fc1a0d6d414cac1a357ed4ee0472fa53f753de7f1cc4015cf453db34ddf42441f700c136566c8d17f65ce78a19ec810
|
7
|
+
data.tar.gz: 30461440ad2c050a41688c12e90bb7ce16df3bd706edb9f51d4bee4dd63dfa906f3e301da044f14be826f28a5ef740f9a2172495a17d6ab2122fb609d31fe2c5
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -174,7 +174,7 @@ require 'thread/pool'
|
|
174
174
|
require 'thread/future'
|
175
175
|
|
176
176
|
pool = Thread.pool 4
|
177
|
-
f = pool {
|
177
|
+
f = pool.future {
|
178
178
|
sleep 5
|
179
179
|
42
|
180
180
|
}
|
@@ -226,4 +226,4 @@ end
|
|
226
226
|
3. Verify new and old specs are green (`rake`)
|
227
227
|
4. Commit your changes (`git commit -am 'Add some feature'`)
|
228
228
|
5. Push to the branch (`git push origin my-new-feature`)
|
229
|
-
6. Create a new Pull Request
|
229
|
+
6. Create a new Pull Request
|
data/lib/thread/channel.rb
CHANGED
@@ -16,7 +16,7 @@ require 'thread'
|
|
16
16
|
# messages are safe to be consumed.
|
17
17
|
class Thread::Channel
|
18
18
|
# Create a channel with optional initial messages and optional channel guard.
|
19
|
-
def initialize
|
19
|
+
def initialize(messages = [], &block)
|
20
20
|
@messages = []
|
21
21
|
@mutex = Mutex.new
|
22
22
|
@check = block
|
@@ -30,7 +30,7 @@ class Thread::Channel
|
|
30
30
|
#
|
31
31
|
# If there's a guard, the value is passed to it, if the guard returns a falsy value
|
32
32
|
# an ArgumentError exception is raised and the message is not sent.
|
33
|
-
def send
|
33
|
+
def send(what)
|
34
34
|
if @check && !@check.call(what)
|
35
35
|
raise ArgumentError, 'guard mismatch'
|
36
36
|
end
|
@@ -47,7 +47,7 @@ class Thread::Channel
|
|
47
47
|
# Receive a message, if there are none the call blocks until there's one.
|
48
48
|
#
|
49
49
|
# If a block is passed, it's used as guard to match to a message.
|
50
|
-
def receive
|
50
|
+
def receive(&block)
|
51
51
|
message = nil
|
52
52
|
found = false
|
53
53
|
|
@@ -83,7 +83,7 @@ class Thread::Channel
|
|
83
83
|
# Receive a message, if there are none the call returns nil.
|
84
84
|
#
|
85
85
|
# If a block is passed, it's used as guard to match to a message.
|
86
|
-
def receive!
|
86
|
+
def receive!(&block)
|
87
87
|
if block
|
88
88
|
@messages.delete_at(@messages.find_index(&block))
|
89
89
|
else
|
@@ -91,7 +91,7 @@ class Thread::Channel
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
-
|
94
|
+
private
|
95
95
|
def cond?
|
96
96
|
instance_variable_defined? :@cond
|
97
97
|
end
|
@@ -103,7 +103,7 @@ end
|
|
103
103
|
|
104
104
|
class Thread
|
105
105
|
# Helper to create a channel.
|
106
|
-
def self.channel
|
106
|
+
def self.channel(*args, &block)
|
107
107
|
Thread::Channel.new(*args, &block)
|
108
108
|
end
|
109
109
|
end
|
data/lib/thread/every.rb
CHANGED
@@ -18,7 +18,7 @@ class Thread::Every
|
|
18
18
|
Restart = Class.new(Exception)
|
19
19
|
|
20
20
|
# Create an every with the given seconds and block.
|
21
|
-
def initialize
|
21
|
+
def initialize(every, &block)
|
22
22
|
raise ArgumentError, 'no block given' unless block
|
23
23
|
|
24
24
|
@every = every
|
@@ -67,14 +67,14 @@ class Thread::Every
|
|
67
67
|
end
|
68
68
|
|
69
69
|
# @private
|
70
|
-
def self.finalizer
|
70
|
+
def self.finalizer(thread)
|
71
71
|
proc {
|
72
72
|
thread.raise Cancel.new
|
73
73
|
}
|
74
74
|
end
|
75
75
|
|
76
76
|
# Change the number of seconds between each call.
|
77
|
-
def every
|
77
|
+
def every(seconds)
|
78
78
|
@every = seconds
|
79
79
|
|
80
80
|
restart
|
@@ -144,7 +144,7 @@ class Thread::Every
|
|
144
144
|
end
|
145
145
|
|
146
146
|
# Gets the current every value.
|
147
|
-
def value
|
147
|
+
def value(timeout = nil)
|
148
148
|
@mutex.synchronize {
|
149
149
|
if @old
|
150
150
|
cond.wait(@mutex, *timeout)
|
@@ -172,7 +172,7 @@ class Thread::Every
|
|
172
172
|
}
|
173
173
|
end
|
174
174
|
|
175
|
-
|
175
|
+
private
|
176
176
|
def cond?
|
177
177
|
instance_variable_defined? :@cond
|
178
178
|
end
|
@@ -184,14 +184,14 @@ end
|
|
184
184
|
|
185
185
|
class Thread
|
186
186
|
# Helper to create an every
|
187
|
-
def self.every
|
187
|
+
def self.every(every, &block)
|
188
188
|
Thread::Every.new(every, &block)
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
192
|
module Kernel
|
193
193
|
# Helper to create an every
|
194
|
-
def every
|
194
|
+
def every(every, &block)
|
195
195
|
Thread::Every.new(every, &block)
|
196
196
|
end
|
197
197
|
end
|
data/lib/thread/future.rb
CHANGED
@@ -17,7 +17,7 @@ class Thread::Future
|
|
17
17
|
Cancel = Class.new(Exception)
|
18
18
|
|
19
19
|
# Create a future with the passed block and optionally using the passed pool.
|
20
|
-
def initialize
|
20
|
+
def initialize(pool = nil, &block)
|
21
21
|
raise ArgumentError, 'no block given' unless block
|
22
22
|
|
23
23
|
@mutex = Mutex.new
|
@@ -38,7 +38,7 @@ class Thread::Future
|
|
38
38
|
end
|
39
39
|
|
40
40
|
# @private
|
41
|
-
def self.finalizer
|
41
|
+
def self.finalizer(thread)
|
42
42
|
proc {
|
43
43
|
thread.raise Cancel.new
|
44
44
|
}
|
@@ -92,7 +92,7 @@ class Thread::Future
|
|
92
92
|
#
|
93
93
|
# An optional timeout can be passed which will return nil if nothing has been
|
94
94
|
# delivered.
|
95
|
-
def value
|
95
|
+
def value(timeout = nil)
|
96
96
|
raise @exception if exception?
|
97
97
|
|
98
98
|
return @value if delivered?
|
@@ -111,7 +111,7 @@ class Thread::Future
|
|
111
111
|
alias ~ value
|
112
112
|
|
113
113
|
# Do the same as {#value}, but return nil in case of exception.
|
114
|
-
def value!
|
114
|
+
def value!(timeout = nil)
|
115
115
|
begin
|
116
116
|
value(timeout)
|
117
117
|
rescue Exception
|
@@ -121,7 +121,7 @@ class Thread::Future
|
|
121
121
|
|
122
122
|
alias ! value!
|
123
123
|
|
124
|
-
|
124
|
+
private
|
125
125
|
def cond?
|
126
126
|
instance_variable_defined? :@cond
|
127
127
|
end
|
@@ -145,20 +145,20 @@ end
|
|
145
145
|
|
146
146
|
class Thread
|
147
147
|
# Helper to create a future
|
148
|
-
def self.future
|
148
|
+
def self.future(pool = nil, &block)
|
149
149
|
Thread::Future.new(pool, &block)
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
153
|
module Kernel
|
154
154
|
# Helper to create a future.
|
155
|
-
def future
|
155
|
+
def future(pool = nil, &block)
|
156
156
|
Thread::Future.new(pool, &block)
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
160
|
class Thread::Pool
|
161
|
-
def future
|
161
|
+
def future(&block)
|
162
162
|
Thread.future self, &block
|
163
163
|
end
|
164
164
|
end
|
data/lib/thread/pipe.rb
CHANGED
@@ -20,7 +20,7 @@ class Thread::Pipe
|
|
20
20
|
|
21
21
|
# Create a Task which will call the passed function and get input
|
22
22
|
# from the optional parameter and put output in the optional parameter.
|
23
|
-
def initialize
|
23
|
+
def initialize(func, input = Queue.new, output = Queue.new)
|
24
24
|
@input = input
|
25
25
|
@output = output
|
26
26
|
@handling = false
|
@@ -54,7 +54,7 @@ class Thread::Pipe
|
|
54
54
|
# output queue.
|
55
55
|
#
|
56
56
|
# The objects must respond to #enq and #deq, and block on #deq.
|
57
|
-
def initialize
|
57
|
+
def initialize(input = Queue.new, output = Queue.new)
|
58
58
|
@tasks = []
|
59
59
|
|
60
60
|
@input = input
|
@@ -64,7 +64,7 @@ class Thread::Pipe
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# @private
|
67
|
-
def self.finalizer
|
67
|
+
def self.finalizer(tasks)
|
68
68
|
proc {
|
69
69
|
tasks.each(&:kill)
|
70
70
|
}
|
@@ -72,7 +72,7 @@ class Thread::Pipe
|
|
72
72
|
|
73
73
|
# Add a task to the pipe, it must respond to #call and #arity,
|
74
74
|
# and #arity must return 1.
|
75
|
-
def |
|
75
|
+
def |(func)
|
76
76
|
if func.arity != 1
|
77
77
|
raise ArgumentError, 'wrong arity'
|
78
78
|
end
|
@@ -91,7 +91,7 @@ class Thread::Pipe
|
|
91
91
|
end
|
92
92
|
|
93
93
|
# Insert data in the pipe.
|
94
|
-
def enq
|
94
|
+
def enq(data)
|
95
95
|
return if @tasks.empty?
|
96
96
|
|
97
97
|
@input.enq data
|
@@ -103,7 +103,7 @@ class Thread::Pipe
|
|
103
103
|
alias << enq
|
104
104
|
|
105
105
|
# Get an element from the output queue.
|
106
|
-
def deq
|
106
|
+
def deq(non_block = false)
|
107
107
|
@output.deq(non_block)
|
108
108
|
end
|
109
109
|
|
@@ -113,7 +113,7 @@ end
|
|
113
113
|
|
114
114
|
class Thread
|
115
115
|
# Helper to create a pipe.
|
116
|
-
def self.|
|
116
|
+
def self.|(func)
|
117
117
|
Pipe.new | func
|
118
118
|
end
|
119
119
|
end
|
data/lib/thread/pool.rb
CHANGED
@@ -22,11 +22,11 @@ class Thread::Pool
|
|
22
22
|
Timeout = Class.new(Exception)
|
23
23
|
Asked = Class.new(Exception)
|
24
24
|
|
25
|
-
attr_reader :pool, :timeout, :exception, :thread, :started_at
|
25
|
+
attr_reader :pool, :timeout, :exception, :thread, :started_at, :result
|
26
26
|
|
27
27
|
# Create a task in the given pool which will pass the arguments to the
|
28
28
|
# block.
|
29
|
-
def initialize
|
29
|
+
def initialize(pool, *args, &block)
|
30
30
|
@pool = pool
|
31
31
|
@arguments = args
|
32
32
|
@block = block
|
@@ -37,23 +37,34 @@ class Thread::Pool
|
|
37
37
|
@terminated = false
|
38
38
|
end
|
39
39
|
|
40
|
-
def running
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
def running?
|
41
|
+
@running
|
42
|
+
end
|
43
|
+
|
44
|
+
def finished?
|
45
|
+
@finished
|
46
|
+
end
|
47
|
+
|
48
|
+
def timeout?
|
49
|
+
@timedout
|
50
|
+
end
|
51
|
+
|
52
|
+
def terminated?
|
53
|
+
@terminated
|
54
|
+
end
|
44
55
|
|
45
|
-
# Execute the task
|
46
|
-
def execute
|
56
|
+
# Execute the task.
|
57
|
+
def execute
|
47
58
|
return if terminated? || running? || finished?
|
48
59
|
|
49
|
-
@thread =
|
60
|
+
@thread = Thread.current
|
50
61
|
@running = true
|
51
62
|
@started_at = Time.now
|
52
63
|
|
53
64
|
pool.__send__ :wake_up_timeout
|
54
65
|
|
55
66
|
begin
|
56
|
-
@block.call(*@arguments)
|
67
|
+
@result = @block.call(*@arguments)
|
57
68
|
rescue Exception => reason
|
58
69
|
if reason.is_a? Timeout
|
59
70
|
@timedout = true
|
@@ -71,12 +82,12 @@ class Thread::Pool
|
|
71
82
|
end
|
72
83
|
|
73
84
|
# Raise an exception in the thread used by the task.
|
74
|
-
def raise
|
85
|
+
def raise(exception)
|
75
86
|
@thread.raise(exception)
|
76
87
|
end
|
77
88
|
|
78
89
|
# Terminate the exception with an optionally given exception.
|
79
|
-
def terminate!
|
90
|
+
def terminate!(exception = Asked)
|
80
91
|
return if terminated? || finished? || timeout?
|
81
92
|
|
82
93
|
@terminated = true
|
@@ -92,10 +103,10 @@ class Thread::Pool
|
|
92
103
|
end
|
93
104
|
|
94
105
|
# Timeout the task after the given time.
|
95
|
-
def timeout_after
|
106
|
+
def timeout_after(time)
|
96
107
|
@timeout = time
|
97
108
|
|
98
|
-
pool.timeout_for self, time
|
109
|
+
pool.__send__ :timeout_for, self, time
|
99
110
|
|
100
111
|
self
|
101
112
|
end
|
@@ -110,7 +121,7 @@ class Thread::Pool
|
|
110
121
|
#
|
111
122
|
# A default block can be passed, which will be used to {#process} the passed
|
112
123
|
# data.
|
113
|
-
def initialize
|
124
|
+
def initialize(min, max = nil, &block)
|
114
125
|
@min = min
|
115
126
|
@max = max || min
|
116
127
|
@block = block
|
@@ -140,7 +151,9 @@ class Thread::Pool
|
|
140
151
|
end
|
141
152
|
|
142
153
|
# Check if the pool has been shut down.
|
143
|
-
def shutdown
|
154
|
+
def shutdown?
|
155
|
+
!!@shutdown
|
156
|
+
end
|
144
157
|
|
145
158
|
# Check if auto trimming is enabled.
|
146
159
|
def auto_trim?
|
@@ -151,11 +164,15 @@ class Thread::Pool
|
|
151
164
|
# is reached.
|
152
165
|
def auto_trim!
|
153
166
|
@auto_trim = true
|
167
|
+
|
168
|
+
self
|
154
169
|
end
|
155
170
|
|
156
171
|
# Disable auto trimming.
|
157
172
|
def no_auto_trim!
|
158
173
|
@auto_trim = false
|
174
|
+
|
175
|
+
self
|
159
176
|
end
|
160
177
|
|
161
178
|
# Check if idle trimming is enabled.
|
@@ -167,15 +184,19 @@ class Thread::Pool
|
|
167
184
|
# The minimum number of threads is respeced.
|
168
185
|
def idle_trim!(timeout)
|
169
186
|
@idle_trim = timeout
|
187
|
+
|
188
|
+
self
|
170
189
|
end
|
171
190
|
|
172
191
|
# Turn of idle trimming.
|
173
192
|
def no_idle_trim!
|
174
193
|
@idle_trim = nil
|
194
|
+
|
195
|
+
self
|
175
196
|
end
|
176
197
|
|
177
198
|
# Resize the pool with the passed arguments.
|
178
|
-
def resize
|
199
|
+
def resize(min, max = nil)
|
179
200
|
@min = min
|
180
201
|
@max = max || min
|
181
202
|
|
@@ -200,9 +221,9 @@ class Thread::Pool
|
|
200
221
|
def wait(what = :idle)
|
201
222
|
case what
|
202
223
|
when :done
|
203
|
-
|
224
|
+
until done?
|
204
225
|
@done_mutex.synchronize {
|
205
|
-
|
226
|
+
break if _done?
|
206
227
|
|
207
228
|
@done.wait @done_mutex
|
208
229
|
}
|
@@ -233,15 +254,7 @@ class Thread::Pool
|
|
233
254
|
#
|
234
255
|
# If no block is passed the default block will be used if present, an
|
235
256
|
# ArgumentError will be raised otherwise.
|
236
|
-
def process
|
237
|
-
unless block || @block
|
238
|
-
raise ArgumentError, 'you must pass a block'
|
239
|
-
end
|
240
|
-
|
241
|
-
wait.process!(*args, &block)
|
242
|
-
end
|
243
|
-
|
244
|
-
def process! (*args, &block)
|
257
|
+
def process(*args, &block)
|
245
258
|
unless block || @block
|
246
259
|
raise ArgumentError, 'you must pass a block'
|
247
260
|
end
|
@@ -263,11 +276,11 @@ class Thread::Pool
|
|
263
276
|
task
|
264
277
|
end
|
265
278
|
|
266
|
-
alias << process
|
279
|
+
alias << process
|
267
280
|
|
268
281
|
# Trim the unused threads, if forced threads will be trimmed even if there
|
269
282
|
# are tasks waiting.
|
270
|
-
def trim
|
283
|
+
def trim(force = false)
|
271
284
|
@mutex.synchronize {
|
272
285
|
if (force || @waiting > 0) && @spawned - @trim_requests > @min
|
273
286
|
@trim_requests += 1
|
@@ -302,52 +315,28 @@ class Thread::Pool
|
|
302
315
|
@cond.broadcast
|
303
316
|
}
|
304
317
|
|
305
|
-
join
|
306
|
-
|
307
|
-
if @timeout
|
308
|
-
@shutdown = :now
|
309
|
-
|
310
|
-
wake_up_timeout
|
311
|
-
|
312
|
-
@timeout.join
|
313
|
-
end
|
314
|
-
|
315
|
-
self
|
316
|
-
end
|
317
|
-
|
318
|
-
# Join on all threads in the pool.
|
319
|
-
def join
|
320
318
|
until @workers.empty?
|
321
319
|
if worker = @workers.first
|
322
320
|
worker.join
|
323
321
|
end
|
324
322
|
end
|
325
323
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
# Define a timeout for a task.
|
330
|
-
def timeout_for (task, timeout)
|
331
|
-
unless @timeout
|
332
|
-
spawn_timeout_thread
|
333
|
-
end
|
334
|
-
|
335
|
-
@mutex.synchronize {
|
336
|
-
@timeouts[task] = timeout
|
324
|
+
if @timeout
|
325
|
+
@shutdown = :now
|
337
326
|
|
338
327
|
wake_up_timeout
|
339
|
-
|
328
|
+
|
329
|
+
@timeout.join
|
330
|
+
end
|
340
331
|
end
|
341
332
|
|
342
333
|
# Shutdown the pool after a given amount of time.
|
343
|
-
def shutdown_after
|
334
|
+
def shutdown_after(timeout)
|
344
335
|
Thread.new {
|
345
336
|
sleep timeout
|
346
337
|
|
347
338
|
shutdown
|
348
339
|
}
|
349
|
-
|
350
|
-
self
|
351
340
|
end
|
352
341
|
|
353
342
|
class << self
|
@@ -358,6 +347,18 @@ class Thread::Pool
|
|
358
347
|
end
|
359
348
|
|
360
349
|
private
|
350
|
+
def timeout_for(task, timeout)
|
351
|
+
unless @timeout
|
352
|
+
spawn_timeout_thread
|
353
|
+
end
|
354
|
+
|
355
|
+
@mutex.synchronize {
|
356
|
+
@timeouts[task] = timeout
|
357
|
+
|
358
|
+
wake_up_timeout
|
359
|
+
}
|
360
|
+
end
|
361
|
+
|
361
362
|
def wake_up_timeout
|
362
363
|
if defined? @pipes
|
363
364
|
@pipes.last.write_nonblock 'x' rescue nil
|
@@ -401,7 +402,7 @@ private
|
|
401
402
|
@todo.shift
|
402
403
|
} or break
|
403
404
|
|
404
|
-
task.execute
|
405
|
+
task.execute
|
405
406
|
|
406
407
|
break if @shutdown == :now
|
407
408
|
|
@@ -471,7 +472,7 @@ end
|
|
471
472
|
|
472
473
|
class Thread
|
473
474
|
# Helper to create a pool.
|
474
|
-
def self.pool
|
475
|
+
def self.pool(*args, &block)
|
475
476
|
Thread::Pool.new(*args, &block)
|
476
477
|
end
|
477
478
|
end
|
data/lib/thread/process.rb
CHANGED
@@ -17,20 +17,20 @@ class Thread::Process
|
|
17
17
|
@@processes ||= {}
|
18
18
|
end
|
19
19
|
|
20
|
-
def self.register
|
20
|
+
def self.register(name, process)
|
21
21
|
all[name] = process
|
22
22
|
end
|
23
23
|
|
24
|
-
def self.unregister
|
24
|
+
def self.unregister(name)
|
25
25
|
all.delete(name)
|
26
26
|
end
|
27
27
|
|
28
|
-
def self.[]
|
28
|
+
def self.[](name)
|
29
29
|
all[name]
|
30
30
|
end
|
31
31
|
|
32
32
|
# Create a new process executing the block.
|
33
|
-
def initialize
|
33
|
+
def initialize(&block)
|
34
34
|
@channel = Thread::Channel.new
|
35
35
|
|
36
36
|
Thread.new {
|
@@ -41,7 +41,7 @@ class Thread::Process
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Send a message to the process.
|
44
|
-
def send
|
44
|
+
def send(what)
|
45
45
|
unless @channel
|
46
46
|
raise RuntimeError, 'the process has terminated'
|
47
47
|
end
|
@@ -53,7 +53,7 @@ class Thread::Process
|
|
53
53
|
|
54
54
|
alias << send
|
55
55
|
|
56
|
-
|
56
|
+
private
|
57
57
|
def receive
|
58
58
|
@channel.receive
|
59
59
|
end
|
@@ -65,7 +65,7 @@ end
|
|
65
65
|
|
66
66
|
class Thread
|
67
67
|
# Helper to create a process.
|
68
|
-
def self.process
|
68
|
+
def self.process(&block)
|
69
69
|
Thread::Process.new(&block)
|
70
70
|
end
|
71
71
|
end
|
data/lib/thread/promise.rb
CHANGED
@@ -27,7 +27,7 @@ class Thread::Promise
|
|
27
27
|
alias realized? delivered?
|
28
28
|
|
29
29
|
# Deliver a value.
|
30
|
-
def deliver
|
30
|
+
def deliver(value)
|
31
31
|
return self if delivered?
|
32
32
|
|
33
33
|
@mutex.synchronize {
|
@@ -46,7 +46,7 @@ class Thread::Promise
|
|
46
46
|
#
|
47
47
|
# An optional timeout can be passed which will return nil if nothing has been
|
48
48
|
# delivered.
|
49
|
-
def value
|
49
|
+
def value(timeout = nil)
|
50
50
|
return @value if delivered?
|
51
51
|
|
52
52
|
@mutex.synchronize {
|
@@ -58,7 +58,7 @@ class Thread::Promise
|
|
58
58
|
|
59
59
|
alias ~ value
|
60
60
|
|
61
|
-
|
61
|
+
private
|
62
62
|
def cond?
|
63
63
|
instance_variable_defined? :@cond
|
64
64
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'thread/pool'
|
2
|
+
|
3
|
+
describe Thread::Pool do
|
4
|
+
it 'creates a new pool with the given amount of threads' do
|
5
|
+
pool = Thread.pool(4)
|
6
|
+
|
7
|
+
expect(pool.spawned).to eq(4)
|
8
|
+
|
9
|
+
pool.shutdown
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'creates a new pool with the given amount of threads without spawning more than min' do
|
13
|
+
pool = Thread.pool(4, 8)
|
14
|
+
|
15
|
+
expect(pool.spawned).to eq(4)
|
16
|
+
|
17
|
+
pool.shutdown
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'properly reports the backlog length' do
|
21
|
+
pool = Thread.pool(2)
|
22
|
+
|
23
|
+
pool.process { sleep 0.5 }
|
24
|
+
pool.process { sleep 0.5 }
|
25
|
+
pool.process { sleep 0.5 }
|
26
|
+
|
27
|
+
sleep 0.25
|
28
|
+
|
29
|
+
expect(pool.backlog).to eq(1)
|
30
|
+
|
31
|
+
pool.shutdown
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'properly reports the pool is done' do
|
35
|
+
pool = Thread.pool(2)
|
36
|
+
|
37
|
+
pool.process { sleep 0.25 }
|
38
|
+
pool.process { sleep 0.25 }
|
39
|
+
pool.process { sleep 0.25 }
|
40
|
+
|
41
|
+
expect(pool.done?).to be(false)
|
42
|
+
|
43
|
+
sleep 0.75
|
44
|
+
|
45
|
+
expect(pool.done?).to be(true)
|
46
|
+
|
47
|
+
pool.shutdown
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'properly reports the pool is idle' do
|
51
|
+
pool = Thread.pool(2)
|
52
|
+
|
53
|
+
pool.process { sleep 0.25 }
|
54
|
+
pool.process { sleep 0.5 }
|
55
|
+
|
56
|
+
expect(pool.idle?).to be(false)
|
57
|
+
|
58
|
+
sleep 0.30
|
59
|
+
|
60
|
+
expect(pool.idle?).to be(true)
|
61
|
+
|
62
|
+
pool.shutdown
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'properly shutdowns the pool' do
|
66
|
+
result = []
|
67
|
+
pool = Thread.pool(4)
|
68
|
+
|
69
|
+
pool.process { sleep 0.1; result << 1 }
|
70
|
+
pool.process { sleep 0.2; result << 2 }
|
71
|
+
pool.process { sleep 0.3; result << 3 }
|
72
|
+
pool.process { sleep 0.4; result << 4 }
|
73
|
+
|
74
|
+
pool.shutdown
|
75
|
+
|
76
|
+
expect(result).to eq([1, 2, 3, 4])
|
77
|
+
end
|
78
|
+
end
|
data/thread.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "thread"
|
7
|
-
spec.version = "0.
|
7
|
+
spec.version = "0.2.0"
|
8
8
|
spec.authors = ["meh."]
|
9
9
|
spec.email = ["meh@schizofreni.co"]
|
10
10
|
spec.summary = %q{Various extensions to the base thread library.}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thread
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- meh.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -67,6 +67,7 @@ files:
|
|
67
67
|
- spec/thread/every_spec.rb
|
68
68
|
- spec/thread/future_spec.rb
|
69
69
|
- spec/thread/pipe_spec.rb
|
70
|
+
- spec/thread/pool_spec.rb
|
70
71
|
- spec/thread/promise_spec.rb
|
71
72
|
- thread.gemspec
|
72
73
|
homepage: http://github.com/meh/ruby-thread
|
@@ -99,5 +100,6 @@ test_files:
|
|
99
100
|
- spec/thread/every_spec.rb
|
100
101
|
- spec/thread/future_spec.rb
|
101
102
|
- spec/thread/pipe_spec.rb
|
103
|
+
- spec/thread/pool_spec.rb
|
102
104
|
- spec/thread/promise_spec.rb
|
103
105
|
has_rdoc:
|