concurrent-ruby 0.9.2-java → 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
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