concurrent-ruby 0.7.0.rc0-x64-mingw32 → 0.7.0.rc1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +13 -8
  3. data/lib/2.0/concurrent_ruby_ext.so +0 -0
  4. data/lib/concurrent.rb +0 -1
  5. data/lib/concurrent/actress.rb +10 -6
  6. data/lib/concurrent/actress/core.rb +1 -1
  7. data/lib/concurrent/async.rb +39 -74
  8. data/lib/concurrent/atomic.rb +21 -1
  9. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +1 -0
  10. data/lib/concurrent/atomic_reference/direct_update.rb +22 -0
  11. data/lib/concurrent/atomic_reference/jruby.rb +2 -0
  12. data/lib/concurrent/atomic_reference/mutex_atomic.rb +36 -6
  13. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +8 -7
  14. data/lib/concurrent/atomic_reference/rbx.rb +7 -4
  15. data/lib/concurrent/atomic_reference/ruby.rb +2 -0
  16. data/lib/concurrent/executor/executor.rb +118 -70
  17. data/lib/concurrent/executor/immediate_executor.rb +50 -1
  18. data/lib/concurrent/executor/java_fixed_thread_pool.rb +14 -6
  19. data/lib/concurrent/executor/java_single_thread_executor.rb +1 -0
  20. data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -10
  21. data/lib/concurrent/executor/per_thread_executor.rb +80 -4
  22. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +1 -1
  23. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +4 -4
  24. data/lib/concurrent/executor/ruby_single_thread_executor.rb +1 -0
  25. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +2 -0
  26. data/lib/concurrent/executor/serialized_execution.rb +23 -0
  27. data/lib/concurrent/version.rb +1 -1
  28. metadata +2 -4
  29. data/lib/concurrent/atomic_reference/delegated_update.rb +0 -28
  30. data/lib/concurrent/supervisor.rb +0 -343
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- Y2ZkM2QxNTUwZTk3OWE3N2RlNzM1NDQwY2RiZTc0OTAyMzUzNDRhNQ==
4
+ YzQ4MWM1MjIzNjhjNjAzZGViYTk2ODAyNzJiOTIwZjRlOWRhMmVmOQ==
5
5
  data.tar.gz: !binary |-
6
- NTFlMzQ4N2IxYzJkZWFlYjY5OGMzMWZmNDQzYmYwZTQ3YjYxMjQyMg==
6
+ YWVmZmY4MDI3MDZmODIzOGU1MTAwZWU0Y2U3ODU1MTQ5ODY2OTFlOQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OTk5ZTc2MmYxNjE2NWRlY2ZlMjMxNGY0MjkyMGZkNmI1NzFjMDJmMDVkYjQw
10
- NjdjMDIxMWFiNzAwMTk4OGNlNGMxZmI2YTgzZjM5Y2NhODkwOGFmYjEzN2Yz
11
- OWM5OTgwMGIyYzk3NDk4OWZhODRmY2M4ZDRhNWUyN2YyNzUyODk=
9
+ ODY5NTY2MjlmOTU1MmUyMWI5YjZlOTQxZTQ2ZTVlN2EyMmVmZWMxNGY1Nzdl
10
+ ZTk2NGZhNzRjY2I4MWFlM2Q0OTVlZjFlOGU5MjhmZTBkYjE0MWYyYWY4Zjli
11
+ MDY2NzJmZjljNTAwYjM1ZjNiM2RjNjdmMzQ3YjVhYzEyYmQ5OTQ=
12
12
  data.tar.gz: !binary |-
13
- OTMzNGE0Y2I4OTYzZGUwMzE4NWU2ZWQ3YmNhOTAxZDEwZTI3YzUyZjUzZjNk
14
- NTQwNTk4Y2JmNjU5MWZjY2JkNGE5MjIxZGMyYzE4MzQwMDE2ZmUyYjIzYjk1
15
- YjU3MDcxYWZiYTUyOWE1MDkwNDQ2ZWFkNGI2MWUyODUwYzhkYjg=
13
+ NjFkMzE0NWMyYzFiYjFmODIyNjdlMWY0YTc4MmVlNmQ0Nzk2OGZmZDJlZDMw
14
+ ZWYzNzAyNzA5NTczYmQ4YzE2NDhlNDg5MDY3Yzk0M2RhZmVjYmQ4YjllMTE3
15
+ NzAzZmY2ODM3NWM2YTc5ZWQwMDk3N2RkZDU2MDVjYWExNzRmNzQ=
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Concurrent Ruby
2
- [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.png)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Coverage Status](https://coveralls.io/repos/ruby-concurrency/concurrent-ruby/badge.png)](https://coveralls.io/r/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.png)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.png)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.png)](https://gemnasium.com/ruby-concurrency/concurrent-ruby)
2
+ [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.png)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Coverage Status](https://coveralls.io/repos/ruby-concurrency/concurrent-ruby/badge.png)](https://coveralls.io/r/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.png)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.png)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.png)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![Gitter chat](https://badges.gitter.im/ruby-concurrency.png)](https://gitter.im/ruby-concurrency)
3
3
 
4
4
  <table>
5
5
  <tr>
@@ -67,8 +67,6 @@ into several general groups:
67
67
  [Promise](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Promise),
68
68
  [ScheduledTask](https://github.com/ruby-concurrency/concurrent-ruby/wiki/ScheduledTask),
69
69
  and [TimerTask](https://github.com/ruby-concurrency/concurrent-ruby/wiki/TimerTask)
70
- * Erlang-inspired [Supervisor](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Supervisor) and other lifecycle classes/mixins
71
- for managing long-running threads
72
70
  * Thread-safe variables including [M-Structures](https://github.com/ruby-concurrency/concurrent-ruby/wiki/MVar-(M-Structure)),
73
71
  [I-Structures](https://github.com/ruby-concurrency/concurrent-ruby/wiki/IVar-(I-Structure)),
74
72
  [thread-local variables](https://github.com/ruby-concurrency/concurrent-ruby/wiki/ThreadLocalVar),
@@ -133,23 +131,30 @@ sleep(3) # do other stuff
133
131
  task.value #=> 25.96
134
132
  ```
135
133
 
136
- ## Contributors
134
+ ## Maintainers
137
135
 
138
136
  * [Jerry D'Antonio](https://github.com/jdantonio)
139
137
  * [Michele Della Torre](https://github.com/mighe)
140
138
  * [Chris Seaton](https://github.com/chrisseaton)
141
139
  * [Lucas Allan](https://github.com/lucasallan)
142
140
  * [Petr Chalupa](https://github.com/pitr-ch)
143
- * [Ravil Bayramgalin](https://github.com/brainopia)
144
- * [Larry Lv](https://github.com/larrylv)
145
- * [Giuseppe Capizzi](https://github.com/gcapizzi)
141
+
142
+ ### Contributors
143
+
146
144
  * [Bill Dueber](https://github.com/billdueber)
147
145
  * [Brian Shirai](https://github.com/brixen)
148
146
  * [Chip Miller](https://github.com/chip-miller)
147
+ * [Giuseppe Capizzi](https://github.com/gcapizzi)
149
148
  * [Jamie Hodge](https://github.com/jamiehodge)
149
+ * [Larry Lv](https://github.com/larrylv)
150
+ * [Maxim Chechel](https://github.com/maximchick)
151
+ * [Ravil Bayramgalin](https://github.com/brainopia)
152
+ * [René Föhring](https://github.com/rrrene)
153
+ * [Shane Wilton](https://github.com/ShaneWilton)
154
+ * [sheaney](https://github.com/sheaney)
150
155
  * [Zander Hill](https://github.com/zph)
151
156
 
152
- ## Contributing
157
+ ### Contributing
153
158
 
154
159
  1. Fork it
155
160
  2. Create your feature branch (`git checkout -b my-new-feature`)
Binary file
data/lib/concurrent.rb CHANGED
@@ -25,7 +25,6 @@ require 'concurrent/observable'
25
25
  require 'concurrent/options_parser'
26
26
  require 'concurrent/promise'
27
27
  require 'concurrent/scheduled_task'
28
- require 'concurrent/supervisor'
29
28
  require 'concurrent/timer_task'
30
29
  require 'concurrent/tvar'
31
30
 
@@ -11,8 +11,8 @@ module Concurrent
11
11
  # - Inspired by Akka and Erlang.
12
12
  #
13
13
  # Actors are sharing a thread-pool by default which makes them very cheap to create and discard.
14
- # Thousands of actors can be created allowing to brake the program to small maintainable pieces
15
- # without breaking single responsibility principles.
14
+ # Thousands of actors can be created, allowing you to break the program into small maintainable pieces,
15
+ # without violating the single responsibility principle.
16
16
  #
17
17
  # ## What is an actor model?
18
18
  #
@@ -26,7 +26,7 @@ module Concurrent
26
26
  # ## Why?
27
27
  #
28
28
  # Concurrency is hard this is one of many ways how to simplify the problem.
29
- # It is simpler to reason about actors then about locks (and all their possible states).
29
+ # It is simpler to reason about actors than about locks (and all their possible states).
30
30
  #
31
31
  # ## How to use it
32
32
  #
@@ -145,7 +145,7 @@ module Concurrent
145
145
  Thread.current[:__current_actor__]
146
146
  end
147
147
 
148
- # implements ROOT
148
+ # implements the root actor
149
149
  class Root
150
150
  include Context
151
151
  # to allow spawning of new actors, spawn needs to be called inside the parent Actor
@@ -158,8 +158,12 @@ module Concurrent
158
158
  end
159
159
  end
160
160
 
161
+ @root = Delay.new { Core.new(parent: nil, name: '/', class: Root).reference }
162
+
161
163
  # A root actor, a default parent of all actors spawned outside an actor
162
- ROOT = Core.new(parent: nil, name: '/', class: Root).reference
164
+ def self.root
165
+ @root.value
166
+ end
163
167
 
164
168
  # Spawns a new actor.
165
169
  #
@@ -184,7 +188,7 @@ module Concurrent
184
188
  if Actress.current
185
189
  Core.new(spawn_optionify(*args).merge(parent: Actress.current), &block).reference
186
190
  else
187
- ROOT.ask([:spawn, spawn_optionify(*args), block]).value
191
+ root.ask([:spawn, spawn_optionify(*args), block]).value
188
192
  end
189
193
  end
190
194
 
@@ -17,7 +17,7 @@ module Concurrent
17
17
  # @return [String] the name of this instance, it should be uniq (not enforced right now)
18
18
  # @!attribute [r] path
19
19
  # @return [String] a path of this actor. It is used for easier orientation and logging.
20
- # Path is constructed recursively with: `parent.path + self.name` up to a {Actress::ROOT},
20
+ # Path is constructed recursively with: `parent.path + self.name` up to a {Actress.root},
21
21
  # e.g. `/an_actor/its_child`.
22
22
  # (It will also probably form a supervision path (failures will be reported up to parents)
23
23
  # in future versions.)
@@ -3,8 +3,8 @@ require 'concurrent/configuration'
3
3
  require 'concurrent/delay'
4
4
  require 'concurrent/errors'
5
5
  require 'concurrent/ivar'
6
- require 'concurrent/future'
7
- require 'concurrent/executor/thread_pool_executor'
6
+ require 'concurrent/executor/immediate_executor'
7
+ require 'concurrent/executor/serialized_execution'
8
8
 
9
9
  module Concurrent
10
10
 
@@ -124,69 +124,24 @@ module Concurrent
124
124
  end
125
125
  module_function :validate_argc
126
126
 
127
- # Delegates synchronous, thread-safe method calls to the wrapped object.
128
- #
129
- # @!visibility private
130
- class AwaitDelegator # :nodoc:
131
-
132
- # Create a new delegator object wrapping the given `delegate` and
133
- # protecting it with the given `mutex`.
134
- #
135
- # @param [Object] delegate the object to wrap and delegate method calls to
136
- # @param [Mutex] mutex the mutex lock to use when delegating method calls
137
- def initialize(delegate, mutex)
138
- @delegate = delegate
139
- @mutex = mutex
140
- end
141
-
142
- # Delegates method calls to the wrapped object. For performance,
143
- # dynamically defines the given method on the delegator so that
144
- # all future calls to `method` will not be directed here.
145
- #
146
- # @param [Symbol] method the method being called
147
- # @param [Array] args zero or more arguments to the method
148
- #
149
- # @return [IVar] the result of the method call
150
- #
151
- # @raise [NameError] the object does not respond to `method` method
152
- # @raise [ArgumentError] the given `args` do not match the arity of `method`
153
- def method_missing(method, *args, &block)
154
- super unless @delegate.respond_to?(method)
155
- Async::validate_argc(@delegate, method, *args)
156
-
157
- self.define_singleton_method(method) do |*args|
158
- Async::validate_argc(@delegate, method, *args)
159
- ivar = Concurrent::IVar.new
160
- value, reason = nil, nil
161
- begin
162
- @mutex.synchronize do
163
- value = @delegate.send(method, *args, &block)
164
- end
165
- rescue => reason
166
- # caught
167
- ensure
168
- return ivar.complete(reason.nil?, value, reason)
169
- end
170
- end
171
-
172
- self.send(method, *args)
173
- end
174
- end
175
-
176
127
  # Delegates asynchronous, thread-safe method calls to the wrapped object.
177
128
  #
178
129
  # @!visibility private
179
130
  class AsyncDelegator # :nodoc:
180
131
 
181
- # Create a new delegator object wrapping the given `delegate` and
182
- # protecting it with the given `mutex`.
132
+ # Create a new delegator object wrapping the given delegate,
133
+ # protecting it with the given serializer, and executing it on the
134
+ # given executor. Block if necessary.
183
135
  #
184
136
  # @param [Object] delegate the object to wrap and delegate method calls to
185
- # @param [Mutex] mutex the mutex lock to use when delegating method calls
186
- def initialize(delegate, executor, mutex)
137
+ # @param [Concurrent::Delay] executor a `Delay` wrapping the executor on which to execute delegated method calls
138
+ # @param [Concurrent::SerializedExecution] serializer the serializer to use when delegating method calls
139
+ # @param [Boolean] blocking will block awaiting result when `true`
140
+ def initialize(delegate, executor, serializer, blocking = false)
187
141
  @delegate = delegate
188
142
  @executor = executor
189
- @mutex = mutex
143
+ @serializer = serializer
144
+ @blocking = blocking
190
145
  end
191
146
 
192
147
  # Delegates method calls to the wrapped object. For performance,
@@ -206,11 +161,19 @@ module Concurrent
206
161
 
207
162
  self.define_singleton_method(method) do |*args|
208
163
  Async::validate_argc(@delegate, method, *args)
209
- Concurrent::Future.execute(executor: @executor.value) do
210
- @mutex.synchronize do
211
- @delegate.send(method, *args, &block)
164
+ ivar = Concurrent::IVar.new
165
+ value, reason = nil, nil
166
+ @serializer.post(@executor.value) do
167
+ begin
168
+ value = @delegate.send(method, *args, &block)
169
+ rescue => reason
170
+ # caught
171
+ ensure
172
+ ivar.complete(reason.nil?, value, reason)
212
173
  end
213
174
  end
175
+ ivar.value if @blocking
176
+ ivar
214
177
  end
215
178
 
216
179
  self.send(method, *args)
@@ -219,9 +182,9 @@ module Concurrent
219
182
 
220
183
  # Causes the chained method call to be performed asynchronously on the
221
184
  # global thread pool. The method called by this method will return a
222
- # `Future` object in the `:pending` state and the method call will have
185
+ # future object in the `:pending` state and the method call will have
223
186
  # been scheduled on the global thread pool. The final disposition of the
224
- # method call can be obtained by inspecting the returned `Future`.
187
+ # method call can be obtained by inspecting the returned future.
225
188
  #
226
189
  # Before scheduling the method on the global thread pool a best-effort
227
190
  # attempt will be made to validate that the method exists on the object
@@ -238,15 +201,15 @@ module Concurrent
238
201
  # method call. Use *only* protected method calls when sharing the object
239
202
  # between threads.
240
203
  #
241
- # @return [Concurrent::Future] the pending result of the asynchronous operation
204
+ # @return [Concurrent::IVar] the pending result of the asynchronous operation
242
205
  #
243
206
  # @raise [Concurrent::InitializationError] `#init_mutex` has not been called
244
207
  # @raise [NameError] the object does not respond to `method` method
245
208
  # @raise [ArgumentError] the given `args` do not match the arity of `method`
246
209
  #
247
- # @see Concurrent::Future
210
+ # @see Concurrent::IVar
248
211
  def async
249
- raise InitializationError.new('#init_mutex was never called') unless @__async__mutex__
212
+ raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
250
213
  @__async_delegator__.value
251
214
  end
252
215
  alias_method :future, :async
@@ -280,7 +243,7 @@ module Concurrent
280
243
  #
281
244
  # @see Concurrent::IVar
282
245
  def await
283
- raise InitializationError.new('#init_mutex was never called') unless @__async__mutex__
246
+ raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
284
247
  @__await_delegator__.value
285
248
  end
286
249
  alias_method :delay, :await
@@ -290,12 +253,12 @@ module Concurrent
290
253
  # @raise [Concurrent::InitializationError] `#init_mutex` has not been called
291
254
  # @raise [ArgumentError] executor has already been set
292
255
  def executor=(executor)
293
- raise InitializationError.new('#init_mutex was never called') unless @__async__mutex__
294
- @__async__executor__.reconfigure { executor } or
256
+ raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
257
+ @__async_executor__.reconfigure { executor } or
295
258
  raise ArgumentError.new('executor has already been set')
296
259
  end
297
260
 
298
- # Initialize the internal mutex and other synchronization objects. This method
261
+ # Initialize the internal serializer and other synchronization objects. This method
299
262
  # *must* be called from the constructor of the including class or explicitly
300
263
  # by the caller prior to calling any other methods. If `init_mutex` is *not*
301
264
  # called explicitly the async/await/executor methods will raize a
@@ -308,12 +271,14 @@ module Concurrent
308
271
  #
309
272
  # @raise [Concurrent::InitializationError] when called more than once
310
273
  def init_mutex
311
- raise InitializationError.new('#init_mutex was already called') if @__async__mutex__
312
- (@__async__mutex__ = Mutex.new).lock
313
- @__async__executor__ = Delay.new{ Concurrent.configuration.global_operation_pool }
314
- @__await_delegator__ = Delay.new{ AwaitDelegator.new(self, @__async__mutex__) }
315
- @__async_delegator__ = Delay.new{ AsyncDelegator.new(self, @__async__executor__, @__async__mutex__) }
316
- @__async__mutex__.unlock
274
+ raise InitializationError.new('#init_mutex was already called') if @__async_initialized__
275
+ @__async_initialized__ = true
276
+ serializer = Concurrent::SerializedExecution.new
277
+ @__async_executor__ = Delay.new{ Concurrent.configuration.global_operation_pool }
278
+ @__await_delegator__ = Delay.new{ AsyncDelegator.new(
279
+ self, Delay.new{ Concurrent::ImmediateExecutor.new }, serializer, true) }
280
+ @__async_delegator__ = Delay.new{ AsyncDelegator.new(
281
+ self, @__async_executor__, serializer, false) }
317
282
  end
318
283
  end
319
284
  end
@@ -16,30 +16,50 @@ end
16
16
 
17
17
  if defined? Concurrent::JavaAtomic
18
18
 
19
+ # @!macro [attach] atomic_reference
20
+ #
21
+ # An object reference that may be updated atomically.
22
+ #
23
+ # @since 0.7.0.rc0
24
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
25
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html
19
26
  class Concurrent::Atomic < Concurrent::JavaAtomic
20
27
  end
21
28
 
22
29
  elsif defined? Concurrent::CAtomic
23
30
 
31
+ # @!macro [attach] concurrent_update_error
32
+ #
33
+ # This exception may be thrown by methods that have detected concurrent
34
+ # modification of an object when such modification is not permissible.
24
35
  class Concurrent::Atomic < Concurrent::CAtomic
25
36
  end
26
37
 
27
38
  elsif defined? Concurrent::RbxAtomic
28
39
 
40
+ # @!macro atomic_reference
29
41
  class Concurrent::Atomic < Concurrent::RbxAtomic
30
42
  end
31
43
 
32
44
  else
33
45
 
46
+ # @!macro atomic_reference
34
47
  class Concurrent::Atomic < Concurrent::MutexAtomic
35
48
  end
36
49
  end
37
50
 
51
+ # @!macro atomic_reference
38
52
  class Atomic < Concurrent::Atomic
39
53
 
54
+ # @!macro concurrent_update_error
40
55
  ConcurrentUpdateError = Class.new(Concurrent::ConcurrentUpdateError)
41
56
 
42
- def initialize(*args)
57
+ # @!macro [attach] atomic_reference_method_initialize
58
+ #
59
+ # Creates a new Atomic reference with null initial value.
60
+ #
61
+ # @param [Object] value the initial value
62
+ def initialize(value)
43
63
  warn "[DEPRECATED] Please use Concurrent::Atomic instead."
44
64
  super
45
65
  end
@@ -1,5 +1,6 @@
1
1
  module Concurrent
2
2
 
3
+ # @!macro atomic_reference
3
4
  class ConcurrentUpdateError < ThreadError
4
5
  # frozen pre-allocated backtrace to speed ConcurrentUpdateError
5
6
  CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
@@ -4,14 +4,36 @@ module Concurrent
4
4
 
5
5
  # Define update methods that use direct paths
6
6
  module AtomicDirectUpdate
7
+
8
+ # @!macro [attach] atomic_reference_method_update
9
+ #
7
10
  # Pass the current value to the given block, replacing it
8
11
  # with the block's result. May retry if the value changes
9
12
  # during the block's execution.
13
+ #
14
+ # @yield [Object] Calculate a new value for the atomic reference using
15
+ # given (old) value
16
+ # @yieldparam [Object] old_value the starting value of the atomic reference
17
+ #
18
+ # @return [Object] the new value
10
19
  def update
11
20
  true until compare_and_set(old_value = get, new_value = yield(old_value))
12
21
  new_value
13
22
  end
14
23
 
24
+ # @!macro [attach] atomic_reference_method_try_update
25
+ #
26
+ # Pass the current value to the given block, replacing it
27
+ # with the block's result. Raise an exception if the update
28
+ # fails.
29
+ #
30
+ # @yield [Object] Calculate a new value for the atomic reference using
31
+ # given (old) value
32
+ # @yieldparam [Object] old_value the starting value of the atomic reference
33
+ #
34
+ # @return [Object] the new value
35
+ #
36
+ # @raise [Concurrent::ConcurrentUpdateError] if the update fails
15
37
  def try_update
16
38
  old_value = get
17
39
  new_value = yield old_value
@@ -2,6 +2,8 @@ require 'concurrent_ruby_ext'
2
2
  require 'concurrent/atomic_reference/direct_update'
3
3
 
4
4
  module Concurrent
5
+
6
+ # @!macro atomic_reference
5
7
  class JavaAtomic
6
8
  include Concurrent::AtomicDirectUpdate
7
9
  end
@@ -4,26 +4,46 @@ require 'concurrent/atomic_reference/numeric_cas_wrapper'
4
4
 
5
5
  module Concurrent
6
6
 
7
- # Portable/generic (but not very memory or scheduling-efficient) fallback
8
- class MutexAtomic #:nodoc: all
7
+ # @!macro atomic_reference
8
+ class MutexAtomic
9
9
  include Concurrent::AtomicDirectUpdate
10
10
  include Concurrent::AtomicNumericCompareAndSetWrapper
11
11
 
12
+ # @!macro atomic_reference_method_initialize
12
13
  def initialize(value = nil)
13
14
  @mutex = Mutex.new
14
15
  @value = value
15
16
  end
16
17
 
18
+ # @!macro [attach] atomic_reference_method_get
19
+ #
20
+ # Gets the current value.
21
+ #
22
+ # @return [Object] the current value
17
23
  def get
18
24
  @mutex.synchronize { @value }
19
25
  end
20
- alias value get
26
+ alias_method :value, :get
21
27
 
28
+ # @!macro [attach] atomic_reference_method_set
29
+ #
30
+ # Sets to the given value.
31
+ #
32
+ # @param [Object] new_value the new value
33
+ #
34
+ # @return [Object] the new value
22
35
  def set(new_value)
23
36
  @mutex.synchronize { @value = new_value }
24
37
  end
25
- alias value= set
38
+ alias_method :value=, :set
26
39
 
40
+ # @!macro [attach] atomic_reference_method_get_and_set
41
+ #
42
+ # Atomically sets to the given value and returns the old value.
43
+ #
44
+ # @param [Object] new_value the new value
45
+ #
46
+ # @return [Object] the old value
27
47
  def get_and_set(new_value)
28
48
  @mutex.synchronize do
29
49
  old_value = @value
@@ -31,9 +51,19 @@ module Concurrent
31
51
  old_value
32
52
  end
33
53
  end
34
- alias swap get_and_set
54
+ alias_method :swap, :get_and_set
35
55
 
36
- def _compare_and_set(old_value, new_value)
56
+ # @!macro [attach] atomic_reference_method_compare_and_set
57
+ #
58
+ # Atomically sets the value to the given updated value if
59
+ # the current value == the expected value.
60
+ #
61
+ # @param [Object] old_value the expected value
62
+ # @param [Object] new_value the new value
63
+ #
64
+ # @return [Boolean] `true` if successful. A `false` return indicates
65
+ # that the actual value was not equal to the expected value.
66
+ def _compare_and_set(old_value, new_value) #:nodoc:
37
67
  return false unless @mutex.try_lock
38
68
  begin
39
69
  return false unless @value.equal? old_value