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.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -1
  3. data/README.md +86 -120
  4. data/lib/concurrent.rb +14 -5
  5. data/lib/concurrent/agent.rb +587 -0
  6. data/lib/concurrent/array.rb +39 -0
  7. data/lib/concurrent/async.rb +296 -149
  8. data/lib/concurrent/atom.rb +135 -45
  9. data/lib/concurrent/atomic/abstract_thread_local_var.rb +38 -0
  10. data/lib/concurrent/atomic/atomic_boolean.rb +83 -118
  11. data/lib/concurrent/atomic/atomic_fixnum.rb +101 -163
  12. data/lib/concurrent/atomic/atomic_reference.rb +1 -8
  13. data/lib/concurrent/atomic/count_down_latch.rb +62 -103
  14. data/lib/concurrent/atomic/cyclic_barrier.rb +3 -1
  15. data/lib/concurrent/atomic/event.rb +1 -1
  16. data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
  17. data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
  18. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
  19. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
  20. data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
  21. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  22. data/lib/concurrent/atomic/read_write_lock.rb +5 -4
  23. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
  24. data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
  25. data/lib/concurrent/atomic/semaphore.rb +84 -178
  26. data/lib/concurrent/atomic/thread_local_var.rb +65 -294
  27. data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -0
  28. data/lib/concurrent/atomic_reference/jruby.rb +1 -1
  29. data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
  30. data/lib/concurrent/atomic_reference/ruby.rb +1 -1
  31. data/lib/concurrent/atomics.rb +7 -37
  32. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +7 -15
  33. data/lib/concurrent/collection/copy_on_write_observer_set.rb +7 -15
  34. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  35. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  36. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  37. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +144 -0
  38. data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
  39. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  40. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  41. data/lib/concurrent/concern/dereferenceable.rb +9 -24
  42. data/lib/concurrent/concern/logging.rb +1 -1
  43. data/lib/concurrent/concern/obligation.rb +11 -20
  44. data/lib/concurrent/concern/observable.rb +38 -13
  45. data/lib/concurrent/configuration.rb +23 -152
  46. data/lib/concurrent/constants.rb +8 -0
  47. data/lib/concurrent/delay.rb +14 -12
  48. data/lib/concurrent/exchanger.rb +339 -41
  49. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  50. data/lib/concurrent/executor/executor_service.rb +23 -359
  51. data/lib/concurrent/executor/immediate_executor.rb +3 -2
  52. data/lib/concurrent/executor/java_executor_service.rb +100 -0
  53. data/lib/concurrent/executor/java_single_thread_executor.rb +3 -3
  54. data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
  55. data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
  56. data/lib/concurrent/executor/ruby_single_thread_executor.rb +10 -66
  57. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +25 -22
  58. data/lib/concurrent/executor/safe_task_executor.rb +6 -7
  59. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  60. data/lib/concurrent/executor/serialized_execution.rb +10 -33
  61. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  62. data/lib/concurrent/executor/simple_executor_service.rb +1 -10
  63. data/lib/concurrent/executor/single_thread_executor.rb +20 -10
  64. data/lib/concurrent/executor/timer_set.rb +8 -10
  65. data/lib/concurrent/executors.rb +12 -2
  66. data/lib/concurrent/future.rb +6 -4
  67. data/lib/concurrent/hash.rb +35 -0
  68. data/lib/concurrent/immutable_struct.rb +5 -1
  69. data/lib/concurrent/ivar.rb +12 -16
  70. data/lib/concurrent/lazy_register.rb +11 -8
  71. data/lib/concurrent/map.rb +180 -0
  72. data/lib/concurrent/maybe.rb +6 -3
  73. data/lib/concurrent/mutable_struct.rb +7 -6
  74. data/lib/concurrent/mvar.rb +26 -2
  75. data/lib/concurrent/{executor/executor.rb → options.rb} +5 -29
  76. data/lib/concurrent/promise.rb +7 -5
  77. data/lib/concurrent/scheduled_task.rb +13 -71
  78. data/lib/concurrent/settable_struct.rb +5 -4
  79. data/lib/concurrent/synchronization.rb +15 -3
  80. data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  81. data/lib/concurrent/synchronization/abstract_object.rb +7 -146
  82. data/lib/concurrent/synchronization/abstract_struct.rb +2 -3
  83. data/lib/concurrent/synchronization/condition.rb +6 -4
  84. data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  85. data/lib/concurrent/synchronization/jruby_object.rb +44 -0
  86. data/lib/concurrent/synchronization/lock.rb +3 -2
  87. data/lib/concurrent/synchronization/lockable_object.rb +72 -0
  88. data/lib/concurrent/synchronization/mri_lockable_object.rb +71 -0
  89. data/lib/concurrent/synchronization/mri_object.rb +43 -0
  90. data/lib/concurrent/synchronization/object.rb +140 -73
  91. data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
  92. data/lib/concurrent/synchronization/rbx_object.rb +30 -73
  93. data/lib/concurrent/synchronization/volatile.rb +34 -0
  94. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  95. data/lib/concurrent/thread_safe/util.rb +14 -0
  96. data/lib/concurrent/thread_safe/util/adder.rb +74 -0
  97. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +30 -0
  98. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  99. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  100. data/lib/concurrent/thread_safe/util/striped64.rb +241 -0
  101. data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
  102. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  103. data/lib/concurrent/timer_task.rb +3 -4
  104. data/lib/concurrent/tuple.rb +86 -0
  105. data/lib/concurrent/tvar.rb +5 -1
  106. data/lib/concurrent/utility/at_exit.rb +1 -1
  107. data/lib/concurrent/utility/engine.rb +4 -0
  108. data/lib/concurrent/utility/monotonic_time.rb +3 -4
  109. data/lib/concurrent/utility/native_extension_loader.rb +50 -30
  110. data/lib/concurrent/version.rb +2 -2
  111. data/lib/concurrent_ruby_ext.jar +0 -0
  112. metadata +47 -12
  113. data/lib/concurrent/atomic/condition.rb +0 -78
  114. data/lib/concurrent/collection/priority_queue.rb +0 -360
  115. data/lib/concurrent/synchronization/java_object.rb +0 -34
  116. data/lib/concurrent/synchronization/monitor_object.rb +0 -27
  117. data/lib/concurrent/synchronization/mutex_object.rb +0 -43
  118. data/lib/concurrent/utilities.rb +0 -5
  119. data/lib/concurrent/utility/timeout.rb +0 -39
  120. data/lib/concurrent/utility/timer.rb +0 -26
  121. 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::Object
9
+ class SafeTaskExecutor < Synchronization::LockableObject
10
10
 
11
11
  def initialize(task, opts = {})
12
- super()
13
- @task = task
12
+ @task = task
14
13
  @exception_class = opts.fetch(:rescue_exception, false) ? Exception : StandardError
15
- ensure_ivar_visibility!
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 = reason = nil
21
+ value = reason = nil
23
22
 
24
23
  begin
25
- value = @task.call(*args)
24
+ value = @task.call(*args)
26
25
  success = true
27
26
  rescue @exception_class => ex
28
- reason = ex
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 'delegate'
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::Object
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(Executor, Array<Object>, Proc)>] posts array of triplets where
44
- # first is a {Executor}, second is array of args for task, third is a task (Proc)
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
- protected
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
- job.executor.post { work(job) }
79
- true
80
- rescue RejectedExecutionError => ex
81
- false
82
- end
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
- protected
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 set number of threads. The number of threads in the pool
20
- # is set on construction and remains constant. When all threads are busy new
21
- # tasks `#post` to the thread pool are enqueued until a thread becomes available.
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
- # The API and behavior of this class are based on Java's `SingleThreadExecutor`
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
- # handling new tasks that are received when the queue size has
37
- # reached `max_queue` or after the executor has shut down
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/priority_queue'
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
- protected
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::PriorityQueue.new(order: :min)
80
- @task_executor = Executor.executor_from_options(opts) || Concurrent.global_io_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
- # `ExecutorServic` callback called during shutdown.
120
+ # `ExecutorService` callback called during shutdown.
123
121
  #
124
122
  # @!visibility private
125
- def shutdown_execution
123
+ def ns_shutdown_execution
126
124
  @queue.clear
127
125
  @timer_executor.kill
128
126
  stopped_event.set
@@ -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/simple_executor_service'
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'
@@ -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(IVar::NO_VALUE, opts.merge(__task_from_block__: block), &nil)
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 = IVar::NO_VALUE, &block)
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 = Executor.executor_from_options(opts) || Concurrent.global_io_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::Object) do
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)
@@ -1,5 +1,4 @@
1
- require 'thread'
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::Object
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 = NO_VALUE, opts = {}, &block)
66
- if value != NO_VALUE && block_given?
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 = NO_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 = NO_VALUE, &block)
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(self)
156
+ init_obligation
161
157
  self.observers = Collection::CopyOnWriteObserverSet.new
162
158
  set_deref_options(opts)
163
159
 
164
- if value == NO_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 != NO_VALUE) || (! block_given && value == NO_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