concurrent-ruby 0.9.0.pre3-java → 0.9.1-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 +15 -2
- data/README.md +37 -26
- data/lib/concurrent/atomic/atomic_fixnum.rb +29 -8
- data/lib/concurrent/atomic/read_write_lock.rb +11 -11
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +375 -0
- data/lib/concurrent/atomic/thread_local_var.rb +181 -51
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
- data/lib/concurrent/concern/deprecation.rb +10 -3
- data/lib/concurrent/concern/logging.rb +2 -0
- data/lib/concurrent/configuration.rb +56 -38
- data/lib/concurrent/delay.rb +0 -1
- data/lib/concurrent/errors.rb +4 -0
- data/lib/concurrent/executor/executor.rb +2 -1
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +9 -10
- data/lib/concurrent/scheduled_task.rb +41 -41
- data/lib/concurrent/synchronization/java_object.rb +0 -1
- data/lib/concurrent/synchronization/monitor_object.rb +3 -0
- data/lib/concurrent/synchronization/object.rb +5 -0
- data/lib/concurrent/synchronization/rbx_object.rb +21 -8
- data/lib/concurrent/utility/at_exit.rb +7 -7
- data/lib/concurrent/utility/engine.rb +4 -0
- data/lib/concurrent/utility/native_extension_loader.rb +1 -4
- data/lib/concurrent/version.rb +2 -2
- data/lib/concurrent_ruby_ext.jar +0 -0
- metadata +7 -7
- data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +0 -236
data/lib/concurrent/delay.rb
CHANGED
data/lib/concurrent/errors.rb
CHANGED
@@ -15,6 +15,10 @@ module Concurrent
|
|
15
15
|
# Raised when an attempt is made to violate an immutability guarantee.
|
16
16
|
ImmutabilityError = Class.new(Error)
|
17
17
|
|
18
|
+
# Raised when an operation is attempted which is not legal given the
|
19
|
+
# receiver's current state
|
20
|
+
IllegalOperationError = Class.new(Error)
|
21
|
+
|
18
22
|
# Raised when an object's methods are called when it has not been
|
19
23
|
# properly initialized.
|
20
24
|
InitializationError = Class.new(Error)
|
@@ -166,7 +166,7 @@ module Concurrent
|
|
166
166
|
def ns_kill_execution
|
167
167
|
# TODO log out unprocessed tasks in queue
|
168
168
|
# TODO try to shutdown first?
|
169
|
-
@pool.each
|
169
|
+
@pool.each(&:kill)
|
170
170
|
@pool.clear
|
171
171
|
@ready.clear
|
172
172
|
end
|
@@ -297,32 +297,31 @@ module Concurrent
|
|
297
297
|
private
|
298
298
|
|
299
299
|
def create_worker(queue, pool, idletime)
|
300
|
-
Thread.new(queue, pool, idletime) do |
|
300
|
+
Thread.new(queue, pool, idletime) do |my_queue, my_pool, my_idletime|
|
301
301
|
last_message = Concurrent.monotonic_time
|
302
302
|
catch(:stop) do
|
303
303
|
loop do
|
304
304
|
|
305
|
-
case message =
|
305
|
+
case message = my_queue.pop
|
306
306
|
when :idle_test
|
307
|
-
if (Concurrent.monotonic_time - last_message) >
|
308
|
-
|
307
|
+
if (Concurrent.monotonic_time - last_message) > my_idletime
|
308
|
+
my_pool.remove_busy_worker(self)
|
309
309
|
throw :stop
|
310
310
|
else
|
311
|
-
|
311
|
+
my_pool.worker_not_old_enough(self)
|
312
312
|
end
|
313
313
|
|
314
314
|
when :stop
|
315
|
-
|
315
|
+
my_pool.remove_busy_worker(self)
|
316
316
|
throw :stop
|
317
317
|
|
318
318
|
else
|
319
319
|
task, args = message
|
320
|
-
run_task
|
320
|
+
run_task my_pool, task, args
|
321
321
|
last_message = Concurrent.monotonic_time
|
322
322
|
|
323
|
-
|
323
|
+
my_pool.ready_worker(self)
|
324
324
|
end
|
325
|
-
|
326
325
|
end
|
327
326
|
end
|
328
327
|
end
|
@@ -1,56 +1,56 @@
|
|
1
1
|
require 'concurrent/errors'
|
2
2
|
require 'concurrent/ivar'
|
3
|
-
require 'concurrent/configuration'
|
4
3
|
require 'concurrent/collection/copy_on_notify_observer_set'
|
5
4
|
require 'concurrent/executor/executor'
|
6
|
-
require 'concurrent/executor/timer_set'
|
7
5
|
require 'concurrent/utility/monotonic_time'
|
6
|
+
require 'concurrent/concern/deprecation'
|
8
7
|
|
9
8
|
module Concurrent
|
9
|
+
include Concern::Deprecation
|
10
10
|
|
11
11
|
# `ScheduledTask` is a close relative of `Concurrent::Future` but with one
|
12
12
|
# important difference: A `Future` is set to execute as soon as possible
|
13
13
|
# whereas a `ScheduledTask` is set to execute after a specified delay. This
|
14
14
|
# implementation is loosely based on Java's
|
15
|
-
# [ScheduledExecutorService](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html).
|
15
|
+
# [ScheduledExecutorService](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html).
|
16
16
|
# It is a more feature-rich variant of {Concurrent.timer}.
|
17
|
-
#
|
17
|
+
#
|
18
18
|
# The *intended* schedule time of task execution is set on object construction
|
19
19
|
# with the `delay` argument. The delay is a numeric (floating point or integer)
|
20
20
|
# representing a number of seconds in the future. Any other value or a numeric
|
21
21
|
# equal to or less than zero will result in an exception. The *actual* schedule
|
22
22
|
# time of task execution is set when the `execute` method is called.
|
23
|
-
#
|
23
|
+
#
|
24
24
|
# The constructor can also be given zero or more processing options. Currently
|
25
25
|
# the only supported options are those recognized by the
|
26
|
-
# [Dereferenceable](Dereferenceable) module.
|
27
|
-
#
|
26
|
+
# [Dereferenceable](Dereferenceable) module.
|
27
|
+
#
|
28
28
|
# The final constructor argument is a block representing the task to be performed.
|
29
29
|
# If no block is given an `ArgumentError` will be raised.
|
30
|
-
#
|
30
|
+
#
|
31
31
|
# **States**
|
32
|
-
#
|
32
|
+
#
|
33
33
|
# `ScheduledTask` mixes in the [Obligation](Obligation) module thus giving it
|
34
34
|
# "future" behavior. This includes the expected lifecycle states. `ScheduledTask`
|
35
35
|
# has one additional state, however. While the task (block) is being executed the
|
36
36
|
# state of the object will be `:processing`. This additional state is necessary
|
37
|
-
# because it has implications for task cancellation.
|
38
|
-
#
|
37
|
+
# because it has implications for task cancellation.
|
38
|
+
#
|
39
39
|
# **Cancellation**
|
40
|
-
#
|
40
|
+
#
|
41
41
|
# A `:pending` task can be cancelled using the `#cancel` method. A task in any
|
42
42
|
# other state, including `:processing`, cannot be cancelled. The `#cancel`
|
43
43
|
# method returns a boolean indicating the success of the cancellation attempt.
|
44
|
-
# A cancelled `ScheduledTask` cannot be restarted. It is immutable.
|
45
|
-
#
|
44
|
+
# A cancelled `ScheduledTask` cannot be restarted. It is immutable.
|
45
|
+
#
|
46
46
|
# **Obligation and Observation**
|
47
|
-
#
|
47
|
+
#
|
48
48
|
# The result of a `ScheduledTask` can be obtained either synchronously or
|
49
49
|
# asynchronously. `ScheduledTask` mixes in both the [Obligation](Obligation)
|
50
50
|
# module and the
|
51
51
|
# [Observable](http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html)
|
52
52
|
# module from the Ruby standard library. With one exception `ScheduledTask`
|
53
|
-
# behaves identically to [Future](Observable) with regard to these modules.
|
53
|
+
# behaves identically to [Future](Observable) with regard to these modules.
|
54
54
|
#
|
55
55
|
# @!macro copy_options
|
56
56
|
#
|
@@ -59,7 +59,7 @@ module Concurrent
|
|
59
59
|
# require 'concurrent'
|
60
60
|
# require 'thread' # for Queue
|
61
61
|
# require 'open-uri' # for open(uri)
|
62
|
-
#
|
62
|
+
#
|
63
63
|
# class Ticker
|
64
64
|
# def get_year_end_closing(symbol, year)
|
65
65
|
# uri = "http://ichart.finance.yahoo.com/table.csv?s=#{symbol}&a=11&b=01&c=#{year}&d=11&e=31&f=#{year}&g=m"
|
@@ -67,75 +67,75 @@ module Concurrent
|
|
67
67
|
# data[1].split(',')[4].to_f
|
68
68
|
# end
|
69
69
|
# end
|
70
|
-
#
|
70
|
+
#
|
71
71
|
# # Future
|
72
72
|
# price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013) }
|
73
73
|
# price.state #=> :pending
|
74
74
|
# sleep(1) # do other stuff
|
75
75
|
# price.value #=> 63.65
|
76
76
|
# price.state #=> :fulfilled
|
77
|
-
#
|
77
|
+
#
|
78
78
|
# # ScheduledTask
|
79
79
|
# task = Concurrent::ScheduledTask.execute(2){ Ticker.new.get_year_end_closing('INTC', 2013) }
|
80
80
|
# task.state #=> :pending
|
81
81
|
# sleep(3) # do other stuff
|
82
82
|
# task.value #=> 25.96
|
83
|
-
#
|
83
|
+
#
|
84
84
|
# @example Successful task execution
|
85
|
-
#
|
85
|
+
#
|
86
86
|
# task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }
|
87
87
|
# task.state #=> :unscheduled
|
88
88
|
# task.execute
|
89
89
|
# task.state #=> pending
|
90
|
-
#
|
90
|
+
#
|
91
91
|
# # wait for it...
|
92
92
|
# sleep(3)
|
93
|
-
#
|
93
|
+
#
|
94
94
|
# task.unscheduled? #=> false
|
95
95
|
# task.pending? #=> false
|
96
96
|
# task.fulfilled? #=> true
|
97
97
|
# task.rejected? #=> false
|
98
98
|
# task.value #=> 'What does the fox say?'
|
99
|
-
#
|
99
|
+
#
|
100
100
|
# @example One line creation and execution
|
101
|
-
#
|
101
|
+
#
|
102
102
|
# task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }.execute
|
103
103
|
# task.state #=> pending
|
104
|
-
#
|
104
|
+
#
|
105
105
|
# task = Concurrent::ScheduledTask.execute(2){ 'What do you get when you multiply 6 by 9?' }
|
106
106
|
# task.state #=> pending
|
107
|
-
#
|
107
|
+
#
|
108
108
|
# @example Failed task execution
|
109
|
-
#
|
109
|
+
#
|
110
110
|
# task = Concurrent::ScheduledTask.execute(2){ raise StandardError.new('Call me maybe?') }
|
111
111
|
# task.pending? #=> true
|
112
|
-
#
|
112
|
+
#
|
113
113
|
# # wait for it...
|
114
114
|
# sleep(3)
|
115
|
-
#
|
115
|
+
#
|
116
116
|
# task.unscheduled? #=> false
|
117
117
|
# task.pending? #=> false
|
118
118
|
# task.fulfilled? #=> false
|
119
119
|
# task.rejected? #=> true
|
120
120
|
# task.value #=> nil
|
121
|
-
# task.reason #=> #<StandardError: Call me maybe?>
|
122
|
-
#
|
121
|
+
# task.reason #=> #<StandardError: Call me maybe?>
|
122
|
+
#
|
123
123
|
# @example Task execution with observation
|
124
|
-
#
|
124
|
+
#
|
125
125
|
# observer = Class.new{
|
126
126
|
# def update(time, value, reason)
|
127
127
|
# puts "The task completed at #{time} with value '#{value}'"
|
128
128
|
# end
|
129
129
|
# }.new
|
130
|
-
#
|
130
|
+
#
|
131
131
|
# task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }
|
132
132
|
# task.add_observer(observer)
|
133
133
|
# task.execute
|
134
134
|
# task.pending? #=> true
|
135
|
-
#
|
135
|
+
#
|
136
136
|
# # wait for it...
|
137
137
|
# sleep(3)
|
138
|
-
#
|
138
|
+
#
|
139
139
|
# #>> The task completed at 2013-11-07 12:26:09 -0500 with value 'What does the fox say?'
|
140
140
|
#
|
141
141
|
# @!macro monotonic_clock_warning
|
@@ -196,12 +196,12 @@ module Concurrent
|
|
196
196
|
#
|
197
197
|
# @deprecated use {#initial_delay} instead
|
198
198
|
def delay
|
199
|
-
|
199
|
+
deprecated_method 'delay', 'initial_delay'
|
200
200
|
initial_delay
|
201
201
|
end
|
202
202
|
|
203
203
|
# The monotonic time at which the the task is scheduled to be executed.
|
204
|
-
#
|
204
|
+
#
|
205
205
|
# @return [Float] the schedule time or nil if `unscheduled`
|
206
206
|
def schedule_time
|
207
207
|
synchronize { @time }
|
@@ -234,7 +234,7 @@ module Concurrent
|
|
234
234
|
#
|
235
235
|
# @deprecated Use {#processing?} instead.
|
236
236
|
def in_progress?
|
237
|
-
|
237
|
+
deprecated_method 'in_progress?', 'processing?'
|
238
238
|
processing?
|
239
239
|
end
|
240
240
|
|
@@ -260,7 +260,7 @@ module Concurrent
|
|
260
260
|
#
|
261
261
|
# @deprecated Use {#cancel} instead.
|
262
262
|
def stop
|
263
|
-
|
263
|
+
deprecated_method 'stop', 'cancel'
|
264
264
|
cancel
|
265
265
|
end
|
266
266
|
|
@@ -363,7 +363,7 @@ module Concurrent
|
|
363
363
|
# @!visibility private
|
364
364
|
def calculate_delay!(delay)
|
365
365
|
if delay.is_a?(Time)
|
366
|
-
|
366
|
+
deprecated 'Use an interval not a clock time; schedule is now based on a monotonic clock'
|
367
367
|
now = Time.now
|
368
368
|
raise ArgumentError.new('schedule time must be in the future') if delay <= now
|
369
369
|
delay.to_f - now.to_f
|
@@ -2,35 +2,48 @@ module Concurrent
|
|
2
2
|
module Synchronization
|
3
3
|
|
4
4
|
if Concurrent.on_rbx?
|
5
|
-
|
5
|
+
|
6
6
|
# @!visibility private
|
7
7
|
# @!macro internal_implementation_note
|
8
8
|
class RbxObject < AbstractObject
|
9
9
|
def initialize
|
10
|
-
@
|
10
|
+
@__Waiters__ = []
|
11
|
+
@__owner__ = nil
|
11
12
|
ensure_ivar_visibility!
|
12
13
|
end
|
13
14
|
|
14
15
|
protected
|
15
16
|
|
16
17
|
def synchronize(&block)
|
17
|
-
|
18
|
+
if @__owner__ == Thread.current
|
19
|
+
yield
|
20
|
+
else
|
21
|
+
Rubinius.lock(self)
|
22
|
+
begin
|
23
|
+
@__owner__ = Thread.current
|
24
|
+
result = yield
|
25
|
+
ensure
|
26
|
+
@__owner__ = nil
|
27
|
+
Rubinius.unlock(self)
|
28
|
+
result
|
29
|
+
end
|
30
|
+
end
|
18
31
|
end
|
19
32
|
|
20
33
|
def ns_wait(timeout = nil)
|
21
34
|
wchan = Rubinius::Channel.new
|
22
35
|
|
23
36
|
begin
|
24
|
-
@
|
37
|
+
@__Waiters__.push wchan
|
25
38
|
Rubinius.unlock(self)
|
26
39
|
signaled = wchan.receive_timeout timeout
|
27
40
|
ensure
|
28
41
|
Rubinius.lock(self)
|
29
42
|
|
30
|
-
if !signaled && !@
|
43
|
+
if !signaled && !@__Waiters__.delete(wchan)
|
31
44
|
# we timed out, but got signaled afterwards,
|
32
45
|
# so pass that signal on to the next waiter
|
33
|
-
@
|
46
|
+
@__Waiters__.shift << true unless @__Waiters__.empty?
|
34
47
|
end
|
35
48
|
end
|
36
49
|
|
@@ -38,12 +51,12 @@ module Concurrent
|
|
38
51
|
end
|
39
52
|
|
40
53
|
def ns_signal
|
41
|
-
@
|
54
|
+
@__Waiters__.shift << true unless @__Waiters__.empty?
|
42
55
|
self
|
43
56
|
end
|
44
57
|
|
45
58
|
def ns_broadcast
|
46
|
-
@
|
59
|
+
@__Waiters__.shift << true until @__Waiters__.empty?
|
47
60
|
self
|
48
61
|
end
|
49
62
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'logger'
|
2
2
|
require 'concurrent/synchronization'
|
3
3
|
|
4
4
|
module Concurrent
|
@@ -8,11 +8,11 @@ module Concurrent
|
|
8
8
|
#
|
9
9
|
# @!visibility private
|
10
10
|
class AtExitImplementation < Synchronization::Object
|
11
|
-
include
|
11
|
+
include Logger::Severity
|
12
12
|
|
13
13
|
def initialize(*args)
|
14
14
|
super()
|
15
|
-
synchronize { ns_initialize
|
15
|
+
synchronize { ns_initialize(*args) }
|
16
16
|
end
|
17
17
|
|
18
18
|
# Add a handler to be run at `Kernel#at_exit`
|
@@ -46,9 +46,9 @@ module Concurrent
|
|
46
46
|
def install
|
47
47
|
synchronize do
|
48
48
|
@installed ||= begin
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
at_exit { runner }
|
50
|
+
true
|
51
|
+
end
|
52
52
|
self
|
53
53
|
end
|
54
54
|
end
|
@@ -71,7 +71,7 @@ module Concurrent
|
|
71
71
|
begin
|
72
72
|
handler.call
|
73
73
|
rescue => error
|
74
|
-
|
74
|
+
Concurrent.global_logger.call(ERROR, error)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
handlers.keys
|
@@ -25,9 +25,6 @@ module Concurrent
|
|
25
25
|
# may be a Windows cross-compiled native gem
|
26
26
|
require "concurrent/#{RUBY_VERSION[0..2]}/extension"
|
27
27
|
@c_ext_loaded = true
|
28
|
-
end,
|
29
|
-
lambda do
|
30
|
-
warn 'Performance on MRI may be improved with the concurrent-ruby-ext gem. Please see http://concurrent-ruby.com'
|
31
28
|
end]
|
32
29
|
|
33
30
|
tries.each do |try|
|
@@ -45,7 +42,7 @@ module Concurrent
|
|
45
42
|
require 'concurrent_ruby_ext'
|
46
43
|
@java_ext_loaded = true
|
47
44
|
rescue LoadError
|
48
|
-
|
45
|
+
# move on with pure-Ruby implementations
|
49
46
|
end
|
50
47
|
end
|
51
48
|
end
|