concurrent-ruby 0.9.2-java → 1.0.0-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 +49 -1
- data/README.md +86 -120
- data/lib/concurrent.rb +14 -5
- data/lib/concurrent/agent.rb +587 -0
- data/lib/concurrent/array.rb +39 -0
- data/lib/concurrent/async.rb +296 -149
- data/lib/concurrent/atom.rb +135 -45
- data/lib/concurrent/atomic/abstract_thread_local_var.rb +38 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +83 -118
- data/lib/concurrent/atomic/atomic_fixnum.rb +101 -163
- data/lib/concurrent/atomic/atomic_reference.rb +1 -8
- data/lib/concurrent/atomic/count_down_latch.rb +62 -103
- data/lib/concurrent/atomic/cyclic_barrier.rb +3 -1
- data/lib/concurrent/atomic/event.rb +1 -1
- data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
- data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
- data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
- data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
- data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
- data/lib/concurrent/atomic/read_write_lock.rb +5 -4
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
- data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
- data/lib/concurrent/atomic/semaphore.rb +84 -178
- data/lib/concurrent/atomic/thread_local_var.rb +65 -294
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -0
- data/lib/concurrent/atomic_reference/jruby.rb +1 -1
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
- data/lib/concurrent/atomic_reference/ruby.rb +1 -1
- data/lib/concurrent/atomics.rb +7 -37
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +7 -15
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +7 -15
- data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
- data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +144 -0
- data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
- data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
- data/lib/concurrent/concern/dereferenceable.rb +9 -24
- data/lib/concurrent/concern/logging.rb +1 -1
- data/lib/concurrent/concern/obligation.rb +11 -20
- data/lib/concurrent/concern/observable.rb +38 -13
- data/lib/concurrent/configuration.rb +23 -152
- data/lib/concurrent/constants.rb +8 -0
- data/lib/concurrent/delay.rb +14 -12
- data/lib/concurrent/exchanger.rb +339 -41
- data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
- data/lib/concurrent/executor/executor_service.rb +23 -359
- data/lib/concurrent/executor/immediate_executor.rb +3 -2
- data/lib/concurrent/executor/java_executor_service.rb +100 -0
- data/lib/concurrent/executor/java_single_thread_executor.rb +3 -3
- data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
- data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +10 -66
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +25 -22
- data/lib/concurrent/executor/safe_task_executor.rb +6 -7
- data/lib/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent/executor/serialized_execution.rb +10 -33
- data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent/executor/simple_executor_service.rb +1 -10
- data/lib/concurrent/executor/single_thread_executor.rb +20 -10
- data/lib/concurrent/executor/timer_set.rb +8 -10
- data/lib/concurrent/executors.rb +12 -2
- data/lib/concurrent/future.rb +6 -4
- data/lib/concurrent/hash.rb +35 -0
- data/lib/concurrent/immutable_struct.rb +5 -1
- data/lib/concurrent/ivar.rb +12 -16
- data/lib/concurrent/lazy_register.rb +11 -8
- data/lib/concurrent/map.rb +180 -0
- data/lib/concurrent/maybe.rb +6 -3
- data/lib/concurrent/mutable_struct.rb +7 -6
- data/lib/concurrent/mvar.rb +26 -2
- data/lib/concurrent/{executor/executor.rb → options.rb} +5 -29
- data/lib/concurrent/promise.rb +7 -5
- data/lib/concurrent/scheduled_task.rb +13 -71
- data/lib/concurrent/settable_struct.rb +5 -4
- data/lib/concurrent/synchronization.rb +15 -3
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent/synchronization/abstract_object.rb +7 -146
- data/lib/concurrent/synchronization/abstract_struct.rb +2 -3
- data/lib/concurrent/synchronization/condition.rb +6 -4
- data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent/synchronization/jruby_object.rb +44 -0
- data/lib/concurrent/synchronization/lock.rb +3 -2
- data/lib/concurrent/synchronization/lockable_object.rb +72 -0
- data/lib/concurrent/synchronization/mri_lockable_object.rb +71 -0
- data/lib/concurrent/synchronization/mri_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +140 -73
- data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
- data/lib/concurrent/synchronization/rbx_object.rb +30 -73
- data/lib/concurrent/synchronization/volatile.rb +34 -0
- data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent/thread_safe/util.rb +14 -0
- data/lib/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +30 -0
- data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +241 -0
- data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
- data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
- data/lib/concurrent/timer_task.rb +3 -4
- data/lib/concurrent/tuple.rb +86 -0
- data/lib/concurrent/tvar.rb +5 -1
- data/lib/concurrent/utility/at_exit.rb +1 -1
- data/lib/concurrent/utility/engine.rb +4 -0
- data/lib/concurrent/utility/monotonic_time.rb +3 -4
- data/lib/concurrent/utility/native_extension_loader.rb +50 -30
- data/lib/concurrent/version.rb +2 -2
- data/lib/concurrent_ruby_ext.jar +0 -0
- metadata +47 -12
- data/lib/concurrent/atomic/condition.rb +0 -78
- data/lib/concurrent/collection/priority_queue.rb +0 -360
- data/lib/concurrent/synchronization/java_object.rb +0 -34
- data/lib/concurrent/synchronization/monitor_object.rb +0 -27
- data/lib/concurrent/synchronization/mutex_object.rb +0 -43
- data/lib/concurrent/utilities.rb +0 -5
- data/lib/concurrent/utility/timeout.rb +0 -39
- data/lib/concurrent/utility/timer.rb +0 -26
- data/lib/concurrent_ruby.rb +0 -2
@@ -6,26 +6,25 @@ module Concurrent
|
|
6
6
|
# success - indicating if the callable has been executed without errors
|
7
7
|
# value - filled by the callable result if it has been executed without errors, nil otherwise
|
8
8
|
# reason - the error risen by the callable if it has been executed with errors, nil otherwise
|
9
|
-
class SafeTaskExecutor < Synchronization::
|
9
|
+
class SafeTaskExecutor < Synchronization::LockableObject
|
10
10
|
|
11
11
|
def initialize(task, opts = {})
|
12
|
-
|
13
|
-
@task = task
|
12
|
+
@task = task
|
14
13
|
@exception_class = opts.fetch(:rescue_exception, false) ? Exception : StandardError
|
15
|
-
|
14
|
+
super() # ensures visibility
|
16
15
|
end
|
17
16
|
|
18
17
|
# @return [Array]
|
19
18
|
def execute(*args)
|
20
19
|
synchronize do
|
21
20
|
success = false
|
22
|
-
value
|
21
|
+
value = reason = nil
|
23
22
|
|
24
23
|
begin
|
25
|
-
value
|
24
|
+
value = @task.call(*args)
|
26
25
|
success = true
|
27
26
|
rescue @exception_class => ex
|
28
|
-
reason
|
27
|
+
reason = ex
|
29
28
|
success = false
|
30
29
|
end
|
31
30
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'concurrent/executor/executor_service'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# Indicates that the including `ExecutorService` guarantees
|
6
|
+
# that all operations will occur in the order they are post and that no
|
7
|
+
# two operations may occur simultaneously. This module provides no
|
8
|
+
# functionality and provides no guarantees. That is the responsibility
|
9
|
+
# of the including class. This module exists solely to allow the including
|
10
|
+
# object to be interrogated for its serialization status.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# class Foo
|
14
|
+
# include Concurrent::SerialExecutor
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# foo = Foo.new
|
18
|
+
#
|
19
|
+
# foo.is_a? Concurrent::ExecutorService #=> true
|
20
|
+
# foo.is_a? Concurrent::SerialExecutor #=> true
|
21
|
+
# foo.serialized? #=> true
|
22
|
+
#
|
23
|
+
# @!visibility private
|
24
|
+
module SerialExecutorService
|
25
|
+
include ExecutorService
|
26
|
+
|
27
|
+
# @!macro executor_service_method_serialized_question
|
28
|
+
#
|
29
|
+
# @note Always returns `true`
|
30
|
+
def serialized?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,12 +1,11 @@
|
|
1
|
-
require '
|
2
|
-
require 'concurrent/executor/executor_service'
|
1
|
+
require 'concurrent/errors'
|
3
2
|
require 'concurrent/concern/logging'
|
4
3
|
require 'concurrent/synchronization'
|
5
4
|
|
6
5
|
module Concurrent
|
7
6
|
|
8
7
|
# Ensures passed jobs in a serialized order never running at the same time.
|
9
|
-
class SerializedExecution < Synchronization::
|
8
|
+
class SerializedExecution < Synchronization::LockableObject
|
10
9
|
include Concern::Logging
|
11
10
|
|
12
11
|
def initialize()
|
@@ -40,8 +39,8 @@ module Concurrent
|
|
40
39
|
# As {#post} but allows to submit multiple tasks at once, it's guaranteed that they will not
|
41
40
|
# be interleaved by other tasks.
|
42
41
|
#
|
43
|
-
# @param [Array<Array(
|
44
|
-
# first is a {
|
42
|
+
# @param [Array<Array(ExecutorService, Array<Object>, Proc)>] posts array of triplets where
|
43
|
+
# first is a {ExecutorService}, second is array of args for task, third is a task (Proc)
|
45
44
|
def posts(posts)
|
46
45
|
# if can_overflow?
|
47
46
|
# raise ArgumentError, 'SerializedExecution does not support thread-pools which can overflow'
|
@@ -66,7 +65,7 @@ module Concurrent
|
|
66
65
|
true
|
67
66
|
end
|
68
67
|
|
69
|
-
|
68
|
+
private
|
70
69
|
|
71
70
|
def ns_initialize
|
72
71
|
@being_executed = false
|
@@ -75,11 +74,11 @@ module Concurrent
|
|
75
74
|
|
76
75
|
def call_job(job)
|
77
76
|
did_it_run = begin
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
77
|
+
job.executor.post { work(job) }
|
78
|
+
true
|
79
|
+
rescue RejectedExecutionError => ex
|
80
|
+
false
|
81
|
+
end
|
83
82
|
|
84
83
|
# TODO not the best idea to run it myself
|
85
84
|
unless did_it_run
|
@@ -105,26 +104,4 @@ module Concurrent
|
|
105
104
|
call_job job if job
|
106
105
|
end
|
107
106
|
end
|
108
|
-
|
109
|
-
# A wrapper/delegator for any `ExecutorService` that
|
110
|
-
# guarantees serialized execution of tasks.
|
111
|
-
#
|
112
|
-
# @see [SimpleDelegator](http://www.ruby-doc.org/stdlib-2.1.2/libdoc/delegate/rdoc/SimpleDelegator.html)
|
113
|
-
# @see Concurrent::SerializedExecution
|
114
|
-
class SerializedExecutionDelegator < SimpleDelegator
|
115
|
-
include SerialExecutorService
|
116
|
-
|
117
|
-
def initialize(executor)
|
118
|
-
@executor = executor
|
119
|
-
@serializer = SerializedExecution.new
|
120
|
-
super(executor)
|
121
|
-
end
|
122
|
-
|
123
|
-
# @!macro executor_service_method_post
|
124
|
-
def post(*args, &task)
|
125
|
-
Kernel.raise ArgumentError.new('no block given') unless block_given?
|
126
|
-
return false unless running?
|
127
|
-
@serializer.post(@executor, *args, &task)
|
128
|
-
end
|
129
|
-
end
|
130
107
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'concurrent/executor/serial_executor_service'
|
3
|
+
require 'concurrent/executor/serialized_execution'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# A wrapper/delegator for any `ExecutorService` that
|
8
|
+
# guarantees serialized execution of tasks.
|
9
|
+
#
|
10
|
+
# @see [SimpleDelegator](http://www.ruby-doc.org/stdlib-2.1.2/libdoc/delegate/rdoc/SimpleDelegator.html)
|
11
|
+
# @see Concurrent::SerializedExecution
|
12
|
+
class SerializedExecutionDelegator < SimpleDelegator
|
13
|
+
include SerialExecutorService
|
14
|
+
|
15
|
+
def initialize(executor)
|
16
|
+
@executor = executor
|
17
|
+
@serializer = SerializedExecution.new
|
18
|
+
super(executor)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @!macro executor_service_method_post
|
22
|
+
def post(*args, &task)
|
23
|
+
raise ArgumentError.new('no block given') unless block_given?
|
24
|
+
return false unless running?
|
25
|
+
@serializer.post(@executor, *args, &task)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -89,7 +89,7 @@ module Concurrent
|
|
89
89
|
@stopped.wait(timeout)
|
90
90
|
end
|
91
91
|
|
92
|
-
|
92
|
+
private
|
93
93
|
|
94
94
|
def ns_initialize
|
95
95
|
@running = Concurrent::AtomicBoolean.new(true)
|
@@ -97,13 +97,4 @@ module Concurrent
|
|
97
97
|
@count = Concurrent::AtomicFixnum.new(0)
|
98
98
|
end
|
99
99
|
end
|
100
|
-
|
101
|
-
# @deprecated
|
102
|
-
class PerThreadExecutor < SimpleExecutorService
|
103
|
-
|
104
|
-
def initialize
|
105
|
-
deprecated 'use SimpleExecutorService instead'
|
106
|
-
super
|
107
|
-
end
|
108
|
-
end
|
109
100
|
end
|
@@ -16,15 +16,22 @@ module Concurrent
|
|
16
16
|
|
17
17
|
# @!macro [attach] single_thread_executor
|
18
18
|
#
|
19
|
-
# A thread pool with a
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# Should a thread crash for any reason the thread will immediately be removed
|
23
|
-
# from the pool and replaced.
|
19
|
+
# A thread pool with a single thread an unlimited queue. Should the thread
|
20
|
+
# die for any reason it will be removed and replaced, thus ensuring that
|
21
|
+
# the executor will always remain viable and available to process jobs.
|
24
22
|
#
|
25
|
-
#
|
23
|
+
# A common pattern for background processing is to create a single thread
|
24
|
+
# on which an infinite loop is run. The thread's loop blocks on an input
|
25
|
+
# source (perhaps blocking I/O or a queue) and processes each input as it
|
26
|
+
# is received. This pattern has several issues. The thread itself is highly
|
27
|
+
# susceptible to errors during processing. Also, the thread itself must be
|
28
|
+
# constantly monitored and restarted should it die. `SingleThreadExecutor`
|
29
|
+
# encapsulates all these bahaviors. The task processor is highly resilient
|
30
|
+
# to errors from within tasks. Also, should the thread die it will
|
31
|
+
# automatically be restarted.
|
32
|
+
#
|
33
|
+
# The API and behavior of this class are based on Java's `SingleThreadExecutor`.
|
26
34
|
#
|
27
|
-
# @!macro thread_pool_options
|
28
35
|
# @!macro abstract_executor_service_public_api
|
29
36
|
class SingleThreadExecutor < SingleThreadExecutorImplementation
|
30
37
|
|
@@ -32,9 +39,12 @@ module Concurrent
|
|
32
39
|
#
|
33
40
|
# Create a new thread pool.
|
34
41
|
#
|
35
|
-
# @option opts [Symbol] :fallback_policy (:discard) the policy for
|
36
|
-
#
|
37
|
-
#
|
42
|
+
# @option opts [Symbol] :fallback_policy (:discard) the policy for handling new
|
43
|
+
# tasks that are received when the queue size has reached
|
44
|
+
# `max_queue` or the executor has shut down
|
45
|
+
#
|
46
|
+
# @raise [ArgumentError] if `:fallback_policy` is not one of the values specified
|
47
|
+
# in `FALLBACK_POLICIES`
|
38
48
|
#
|
39
49
|
# @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
|
40
50
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
|
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'concurrent/scheduled_task'
|
2
2
|
require 'concurrent/atomic/event'
|
3
|
-
require 'concurrent/collection/
|
4
|
-
require 'concurrent/concern/deprecation'
|
3
|
+
require 'concurrent/collection/non_concurrent_priority_queue'
|
5
4
|
require 'concurrent/executor/executor_service'
|
6
5
|
require 'concurrent/executor/single_thread_executor'
|
7
6
|
|
8
7
|
module Concurrent
|
9
8
|
|
9
|
+
autoload :Options, 'concurrent/options'
|
10
|
+
|
10
11
|
# Executes a collection of tasks, each after a given delay. A master task
|
11
12
|
# monitors the set and schedules each task for execution at the appropriate
|
12
13
|
# time. Tasks are run on the global thread pool or on the supplied executor.
|
@@ -16,7 +17,6 @@ module Concurrent
|
|
16
17
|
#
|
17
18
|
# @!macro monotonic_clock_warning
|
18
19
|
class TimerSet < RubyExecutorService
|
19
|
-
extend Concern::Deprecation
|
20
20
|
|
21
21
|
# Create a new set of timed tasks.
|
22
22
|
#
|
@@ -45,8 +45,6 @@ module Concurrent
|
|
45
45
|
#
|
46
46
|
# @raise [ArgumentError] if the intended execution time is not in the future.
|
47
47
|
# @raise [ArgumentError] if no block is given.
|
48
|
-
#
|
49
|
-
# @!macro deprecated_scheduling_by_clock_time
|
50
48
|
def post(delay, *args, &task)
|
51
49
|
raise ArgumentError.new('no block given') unless block_given?
|
52
50
|
return false unless running?
|
@@ -69,15 +67,15 @@ module Concurrent
|
|
69
67
|
|
70
68
|
private :<<
|
71
69
|
|
72
|
-
|
70
|
+
private
|
73
71
|
|
74
72
|
# Initialize the object.
|
75
73
|
#
|
76
74
|
# @param [Hash] opts the options to create the object with.
|
77
75
|
# @!visibility private
|
78
76
|
def ns_initialize(opts)
|
79
|
-
@queue = Collection::
|
80
|
-
@task_executor =
|
77
|
+
@queue = Collection::NonConcurrentPriorityQueue.new(order: :min)
|
78
|
+
@task_executor = Options.executor_from_options(opts) || Concurrent.global_io_executor
|
81
79
|
@timer_executor = SingleThreadExecutor.new
|
82
80
|
@condition = Event.new
|
83
81
|
self.auto_terminate = opts.fetch(:auto_terminate, true)
|
@@ -119,10 +117,10 @@ module Concurrent
|
|
119
117
|
synchronize{ @queue.delete(task) }
|
120
118
|
end
|
121
119
|
|
122
|
-
# `
|
120
|
+
# `ExecutorService` callback called during shutdown.
|
123
121
|
#
|
124
122
|
# @!visibility private
|
125
|
-
def
|
123
|
+
def ns_shutdown_execution
|
126
124
|
@queue.clear
|
127
125
|
@timer_executor.kill
|
128
126
|
stopped_event.set
|
data/lib/concurrent/executors.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
|
+
require 'concurrent/executor/abstract_executor_service'
|
1
2
|
require 'concurrent/executor/cached_thread_pool'
|
3
|
+
require 'concurrent/executor/executor_service'
|
2
4
|
require 'concurrent/executor/fixed_thread_pool'
|
3
5
|
require 'concurrent/executor/immediate_executor'
|
4
6
|
require 'concurrent/executor/indirect_immediate_executor'
|
7
|
+
require 'concurrent/executor/java_executor_service'
|
8
|
+
require 'concurrent/executor/java_single_thread_executor'
|
9
|
+
require 'concurrent/executor/java_thread_pool_executor'
|
10
|
+
require 'concurrent/executor/ruby_executor_service'
|
11
|
+
require 'concurrent/executor/ruby_single_thread_executor'
|
12
|
+
require 'concurrent/executor/ruby_thread_pool_executor'
|
13
|
+
require 'concurrent/executor/cached_thread_pool'
|
5
14
|
require 'concurrent/executor/safe_task_executor'
|
6
|
-
require 'concurrent/executor/
|
15
|
+
require 'concurrent/executor/serial_executor_service'
|
16
|
+
require 'concurrent/executor/serialized_execution'
|
17
|
+
require 'concurrent/executor/serialized_execution_delegator'
|
7
18
|
require 'concurrent/executor/single_thread_executor'
|
8
19
|
require 'concurrent/executor/thread_pool_executor'
|
9
20
|
require 'concurrent/executor/timer_set'
|
10
|
-
require 'concurrent/executor/serialized_execution'
|
data/lib/concurrent/future.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'thread'
|
2
|
+
require 'concurrent/constants'
|
2
3
|
require 'concurrent/errors'
|
3
4
|
require 'concurrent/ivar'
|
4
|
-
require 'concurrent/executor/executor'
|
5
5
|
require 'concurrent/executor/safe_task_executor'
|
6
6
|
|
7
7
|
module Concurrent
|
8
8
|
|
9
|
+
autoload :Options, 'concurrent/options'
|
10
|
+
|
9
11
|
# {include:file:doc/future.md}
|
10
12
|
#
|
11
13
|
# @!macro copy_options
|
@@ -27,7 +29,7 @@ module Concurrent
|
|
27
29
|
# @raise [ArgumentError] if no block is given
|
28
30
|
def initialize(opts = {}, &block)
|
29
31
|
raise ArgumentError.new('no block given') unless block_given?
|
30
|
-
super(
|
32
|
+
super(NULL, opts.merge(__task_from_block__: block), &nil)
|
31
33
|
end
|
32
34
|
|
33
35
|
# Execute an `:unscheduled` `Future`. Immediately sets the state to `:pending` and
|
@@ -74,7 +76,7 @@ module Concurrent
|
|
74
76
|
end
|
75
77
|
|
76
78
|
# @!macro ivar_set_method
|
77
|
-
def set(value =
|
79
|
+
def set(value = NULL, &block)
|
78
80
|
check_for_block_or_value!(block_given?, value)
|
79
81
|
synchronize do
|
80
82
|
if @state != :unscheduled
|
@@ -129,7 +131,7 @@ module Concurrent
|
|
129
131
|
super
|
130
132
|
@state = :unscheduled
|
131
133
|
@task = opts[:__task_from_block__]
|
132
|
-
@executor =
|
134
|
+
@executor = Options.executor_from_options(opts) || Concurrent.global_io_executor
|
133
135
|
@args = get_arguments_from(opts)
|
134
136
|
end
|
135
137
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/thread_safe/util'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
if Concurrent.on_cruby?
|
6
|
+
|
7
|
+
# @!macro [attach] concurrent_hash
|
8
|
+
#
|
9
|
+
# A thread-safe subclass of Hash. This version locks against the object
|
10
|
+
# itself for every method call, ensuring only one thread can be reading
|
11
|
+
# or writing at a time. This includes iteration methods like `#each`.
|
12
|
+
#
|
13
|
+
# @see http://ruby-doc.org/core-2.2.0/Hash.html Ruby standard library `Hash`
|
14
|
+
class Hash < ::Hash;
|
15
|
+
end
|
16
|
+
|
17
|
+
elsif Concurrent.on_jruby?
|
18
|
+
require 'jruby/synchronized'
|
19
|
+
|
20
|
+
# @!macro concurrent_hash
|
21
|
+
class Hash < ::Hash
|
22
|
+
include JRuby::Synchronized
|
23
|
+
end
|
24
|
+
|
25
|
+
elsif Concurrent.on_rbx?
|
26
|
+
require 'monitor'
|
27
|
+
require 'concurrent/thread_safe/util/array_hash_rbx'
|
28
|
+
|
29
|
+
# @!macro concurrent_hash
|
30
|
+
class Hash < ::Hash
|
31
|
+
end
|
32
|
+
|
33
|
+
ThreadSafe::Util.make_synchronized_on_rbx Hash
|
34
|
+
end
|
35
|
+
end
|
@@ -9,6 +9,10 @@ module Concurrent
|
|
9
9
|
module ImmutableStruct
|
10
10
|
include Synchronization::AbstractStruct
|
11
11
|
|
12
|
+
def self.included(base)
|
13
|
+
base.safe_initialization!
|
14
|
+
end
|
15
|
+
|
12
16
|
# @!macro struct_values
|
13
17
|
def values
|
14
18
|
ns_values
|
@@ -77,7 +81,7 @@ module Concurrent
|
|
77
81
|
FACTORY.define_struct(clazz_name, args, &block)
|
78
82
|
end
|
79
83
|
|
80
|
-
FACTORY = Class.new(Synchronization::
|
84
|
+
FACTORY = Class.new(Synchronization::LockableObject) do
|
81
85
|
def define_struct(name, members, &block)
|
82
86
|
synchronize do
|
83
87
|
Synchronization::AbstractStruct.define_struct_class(ImmutableStruct, Synchronization::Object, name, members, &block)
|
data/lib/concurrent/ivar.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'concurrent/constants'
|
3
2
|
require 'concurrent/errors'
|
4
3
|
require 'concurrent/collection/copy_on_write_observer_set'
|
5
4
|
require 'concurrent/concern/obligation'
|
@@ -45,13 +44,10 @@ module Concurrent
|
|
45
44
|
# In Proceedings of Workshop on Graph Reduction, 1986.
|
46
45
|
# 2. For recent application:
|
47
46
|
# [DataDrivenFuture in Habanero Java from Rice](http://www.cs.rice.edu/~vs3/hjlib/doc/edu/rice/hj/api/HjDataDrivenFuture.html).
|
48
|
-
class IVar < Synchronization::
|
47
|
+
class IVar < Synchronization::LockableObject
|
49
48
|
include Concern::Obligation
|
50
49
|
include Concern::Observable
|
51
50
|
|
52
|
-
# @!visibility private
|
53
|
-
NO_VALUE = Object.new # :nodoc:
|
54
|
-
|
55
51
|
# Create a new `IVar` in the `:pending` state with the (optional) initial value.
|
56
52
|
#
|
57
53
|
# @param [Object] value the initial value
|
@@ -62,8 +58,8 @@ module Concurrent
|
|
62
58
|
# returning the data
|
63
59
|
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing
|
64
60
|
# the internal value and returning the value returned from the proc
|
65
|
-
def initialize(value =
|
66
|
-
if value !=
|
61
|
+
def initialize(value = NULL, opts = {}, &block)
|
62
|
+
if value != NULL && block_given?
|
67
63
|
raise ArgumentError.new('provide only a value or a block')
|
68
64
|
end
|
69
65
|
super(&nil)
|
@@ -104,16 +100,16 @@ module Concurrent
|
|
104
100
|
|
105
101
|
# @!macro [attach] ivar_set_method
|
106
102
|
# Set the `IVar` to a value and wake or notify all threads waiting on it.
|
107
|
-
#
|
103
|
+
#
|
108
104
|
# @!macro [attach] ivar_set_parameters_and_exceptions
|
109
105
|
# @param [Object] value the value to store in the `IVar`
|
110
106
|
# @yield A block operation to use for setting the value
|
111
107
|
# @raise [ArgumentError] if both a value and a block are given
|
112
108
|
# @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already
|
113
109
|
# been set or otherwise completed
|
114
|
-
#
|
110
|
+
#
|
115
111
|
# @return [IVar] self
|
116
|
-
def set(value =
|
112
|
+
def set(value = NULL)
|
117
113
|
check_for_block_or_value!(block_given?, value)
|
118
114
|
raise MultipleAssignmentError unless compare_and_set_state(:processing, :pending)
|
119
115
|
|
@@ -130,7 +126,7 @@ module Concurrent
|
|
130
126
|
|
131
127
|
# @!macro [attach] ivar_fail_method
|
132
128
|
# Set the `IVar` to failed due to some error and wake or notify all threads waiting on it.
|
133
|
-
#
|
129
|
+
#
|
134
130
|
# @param [Object] reason for the failure
|
135
131
|
# @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already
|
136
132
|
# been set or otherwise completed
|
@@ -145,7 +141,7 @@ module Concurrent
|
|
145
141
|
# @!macro ivar_set_parameters_and_exceptions
|
146
142
|
#
|
147
143
|
# @return [Boolean] true if the value was set else false
|
148
|
-
def try_set(value =
|
144
|
+
def try_set(value = NULL, &block)
|
149
145
|
set(value, &block)
|
150
146
|
true
|
151
147
|
rescue MultipleAssignmentError
|
@@ -157,11 +153,11 @@ module Concurrent
|
|
157
153
|
# @!visibility private
|
158
154
|
def ns_initialize(value, opts)
|
159
155
|
value = yield if block_given?
|
160
|
-
init_obligation
|
156
|
+
init_obligation
|
161
157
|
self.observers = Collection::CopyOnWriteObserverSet.new
|
162
158
|
set_deref_options(opts)
|
163
159
|
|
164
|
-
if value ==
|
160
|
+
if value == NULL
|
165
161
|
@state = :pending
|
166
162
|
else
|
167
163
|
ns_complete_without_notification(true, value, nil)
|
@@ -204,7 +200,7 @@ module Concurrent
|
|
204
200
|
|
205
201
|
# @!visibility private
|
206
202
|
def check_for_block_or_value!(block_given, value) # :nodoc:
|
207
|
-
if (block_given && value !=
|
203
|
+
if (block_given && value != NULL) || (! block_given && value == NULL)
|
208
204
|
raise ArgumentError.new('must set with either a value or a block')
|
209
205
|
end
|
210
206
|
end
|