concurrent-ruby 0.8.0 → 0.9.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -2
  3. data/README.md +103 -54
  4. data/lib/concurrent.rb +34 -14
  5. data/lib/concurrent/async.rb +164 -50
  6. data/lib/concurrent/atom.rb +171 -0
  7. data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
  8. data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
  9. data/lib/concurrent/atomic/atomic_reference.rb +49 -0
  10. data/lib/concurrent/atomic/condition.rb +23 -12
  11. data/lib/concurrent/atomic/count_down_latch.rb +23 -21
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
  13. data/lib/concurrent/atomic/event.rb +33 -42
  14. data/lib/concurrent/atomic/read_write_lock.rb +252 -0
  15. data/lib/concurrent/atomic/semaphore.rb +64 -89
  16. data/lib/concurrent/atomic/thread_local_var.rb +130 -58
  17. data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
  18. data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
  21. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
  22. data/lib/concurrent/atomic_reference/rbx.rb +4 -1
  23. data/lib/concurrent/atomic_reference/ruby.rb +6 -3
  24. data/lib/concurrent/atomics.rb +74 -4
  25. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
  26. data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
  27. data/lib/concurrent/collection/priority_queue.rb +300 -245
  28. data/lib/concurrent/concern/deprecation.rb +27 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +25 -0
  31. data/lib/concurrent/concern/obligation.rb +228 -0
  32. data/lib/concurrent/concern/observable.rb +85 -0
  33. data/lib/concurrent/configuration.rb +226 -112
  34. data/lib/concurrent/dataflow.rb +2 -3
  35. data/lib/concurrent/delay.rb +141 -50
  36. data/lib/concurrent/edge.rb +30 -0
  37. data/lib/concurrent/errors.rb +10 -0
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
  40. data/lib/concurrent/executor/executor.rb +46 -299
  41. data/lib/concurrent/executor/executor_service.rb +521 -0
  42. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
  43. data/lib/concurrent/executor/immediate_executor.rb +9 -9
  44. data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
  45. data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
  46. data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
  47. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  48. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  49. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
  50. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
  51. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  52. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  53. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  54. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  55. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  56. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  57. data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
  58. data/lib/concurrent/executor/timer_set.rb +96 -84
  59. data/lib/concurrent/executors.rb +1 -1
  60. data/lib/concurrent/future.rb +70 -38
  61. data/lib/concurrent/immutable_struct.rb +89 -0
  62. data/lib/concurrent/ivar.rb +152 -60
  63. data/lib/concurrent/lazy_register.rb +40 -20
  64. data/lib/concurrent/maybe.rb +226 -0
  65. data/lib/concurrent/mutable_struct.rb +227 -0
  66. data/lib/concurrent/mvar.rb +44 -43
  67. data/lib/concurrent/promise.rb +208 -134
  68. data/lib/concurrent/scheduled_task.rb +339 -43
  69. data/lib/concurrent/settable_struct.rb +127 -0
  70. data/lib/concurrent/synchronization.rb +17 -0
  71. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  72. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  73. data/lib/concurrent/synchronization/condition.rb +53 -0
  74. data/lib/concurrent/synchronization/java_object.rb +35 -0
  75. data/lib/concurrent/synchronization/lock.rb +32 -0
  76. data/lib/concurrent/synchronization/monitor_object.rb +24 -0
  77. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  78. data/lib/concurrent/synchronization/object.rb +78 -0
  79. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  80. data/lib/concurrent/timer_task.rb +87 -100
  81. data/lib/concurrent/tvar.rb +42 -38
  82. data/lib/concurrent/utilities.rb +3 -1
  83. data/lib/concurrent/utility/at_exit.rb +97 -0
  84. data/lib/concurrent/utility/engine.rb +40 -0
  85. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  86. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  87. data/lib/concurrent/utility/processor_counter.rb +156 -0
  88. data/lib/concurrent/utility/timeout.rb +18 -14
  89. data/lib/concurrent/utility/timer.rb +11 -6
  90. data/lib/concurrent/version.rb +2 -1
  91. data/lib/concurrent_ruby.rb +1 -0
  92. metadata +47 -83
  93. data/lib/concurrent/actor.rb +0 -103
  94. data/lib/concurrent/actor/behaviour.rb +0 -70
  95. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  96. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  97. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  98. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  99. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  100. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  101. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  102. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  103. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  104. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  105. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  106. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  107. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  108. data/lib/concurrent/actor/context.rb +0 -154
  109. data/lib/concurrent/actor/core.rb +0 -217
  110. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  111. data/lib/concurrent/actor/envelope.rb +0 -41
  112. data/lib/concurrent/actor/errors.rb +0 -27
  113. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  114. data/lib/concurrent/actor/public_delegations.rb +0 -40
  115. data/lib/concurrent/actor/reference.rb +0 -81
  116. data/lib/concurrent/actor/root.rb +0 -37
  117. data/lib/concurrent/actor/type_check.rb +0 -48
  118. data/lib/concurrent/actor/utils.rb +0 -10
  119. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  120. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  121. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  122. data/lib/concurrent/actor/utils/pool.rb +0 -59
  123. data/lib/concurrent/actress.rb +0 -3
  124. data/lib/concurrent/agent.rb +0 -209
  125. data/lib/concurrent/atomic.rb +0 -92
  126. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  127. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  128. data/lib/concurrent/atomic/synchronization.rb +0 -51
  129. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  130. data/lib/concurrent/channel/channel.rb +0 -41
  131. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  132. data/lib/concurrent/channel/waitable_list.rb +0 -40
  133. data/lib/concurrent/channels.rb +0 -5
  134. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  135. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  136. data/lib/concurrent/collections.rb +0 -3
  137. data/lib/concurrent/dereferenceable.rb +0 -108
  138. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  139. data/lib/concurrent/logging.rb +0 -20
  140. data/lib/concurrent/obligation.rb +0 -171
  141. data/lib/concurrent/observable.rb +0 -73
  142. data/lib/concurrent/options_parser.rb +0 -52
  143. data/lib/concurrent/utility/processor_count.rb +0 -152
  144. data/lib/extension_helper.rb +0 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c1cb9ee067ce09d0d58e0dbf2b704e9f05f3f23c
4
- data.tar.gz: f70953ed219fd7da3f2011f426ed889e0293e65f
3
+ metadata.gz: 6e100cda902e2d18d80d34e38ec541d11bde399a
4
+ data.tar.gz: a56ad16d5a76aa677befbdf3ad2f7b47b0cc1fcb
5
5
  SHA512:
6
- metadata.gz: 23d3c454c1a17957ddb8c51320ca9ea0f365e8fb2e828b5a27e2db18d42d144679047198fcdb0dc5393349cfbfa84ba801baf5474b009634739a25e8585fb8d8
7
- data.tar.gz: 45ba36f7d1aaba1dd7e5fc7a10a6922a5327c8f975bd4f5cabb2162b2b76b293884688f9bb8cbcfe8b23d61bb8cd4fd7b504b80360a3c28e204935169a67d167
6
+ metadata.gz: 066dcc901e922bb751c79acf6249b693984cda1674adf40efc7dbdd782ca22ff8f313dd4674d282b9b22721522ab03aa481c93399fc94017cc8d90a4c17e2acf
7
+ data.tar.gz: 36d5fe13bebec7e07b3639c65deb455d0bbcb091a11678c05c8664213573179117517d3f2f097d6413a9f71fc09e1193b8ec189ccaa6d1c422779994638015cd
data/CHANGELOG.md CHANGED
@@ -1,11 +1,106 @@
1
- ### Next Release v0.8.0 (25 January 2015)
1
+ ### Next Release v0.9.0 (Target Date: 7 June 2015)
2
+
3
+ * Pure Java implementations of
4
+ - `AtomicBoolean`
5
+ - `AtomicFixnum`
6
+ - `Semaphore`
7
+ * Fixed bug when pruning Ruby thread pools
8
+ * Fixed bug in time calculations within `ScheduledTask`
9
+ * Default `count` in `CountDownLatch` to 1
10
+ * Use monotonic clock for all timers via `Concurrent.monotonic_time`
11
+ - Use `Process.clock_gettime(Process::CLOCK_MONOTONIC)` when available
12
+ - Fallback to `java.lang.System.nanoTime()` on unsupported JRuby versions
13
+ - Pure Ruby implementation for everything else
14
+ - Effects `Concurrent.timer`, `Concurrent.timeout`, `TimerSet`, `TimerTask`, and `ScheduledTask`
15
+ * Deprecated all clock-time based timer scheduling
16
+ - Only support scheduling by delay
17
+ - Effects `Concurrent.timer`, `TimerSet`, and `ScheduledTask`
18
+ * Added new `ReadWriteLock` class
19
+ * Consistent `at_exit` behavior for Java and Ruby thread pools.
20
+ * Added `at_exit` handler to Ruby thread pools (already in Java thread pools)
21
+ - Ruby handler stores the object id and retrieves from `ObjectSpace`
22
+ - JRuby disables `ObjectSpace` by default so that handler stores the object reference
23
+ * Added a `:stop_on_exit` option to thread pools to enable/disable `at_exit` handler
24
+ * Updated thread pool docs to better explain shutting down thread pools
25
+ * Simpler `:executor` option syntax for all abstractions which support this option
26
+ * Added `Executor#auto_terminate?` predicate method (for thread pools)
27
+ * Added `at_exit` handler to `TimerSet`
28
+ * Simplified auto-termination of the global executors
29
+ - Can now disable auto-termination of global executors
30
+ - Added shutdown/kill/wait_for_termination variants for global executors
31
+ * Can now disable auto-termination for *all* executors (the nuclear option)
32
+ * Simplified auto-termination of the global executors
33
+ * Deprecated terms "task pool" and "operation pool"
34
+ - New terms are "io executor" and "fast executor"
35
+ - New functions added with new names
36
+ - Deprecation warnings added to functions referencing old names
37
+ * Moved all thread pool related functions from `Concurrent::Configuration` to `Concurrent`
38
+ - Old functions still exist with deprecation warnings
39
+ - New functions have updated names as appropriate
40
+ * All high-level abstractions default to the "io executor"
41
+ * Fixed bug in `Actor` causing it to prematurely warm global thread pools on gem load
42
+ - This also fixed a `RejectedExecutionError` bug when running with minitest/autorun via JRuby
43
+ * Moved global logger up to the `Concurrent` namespace and refactored the code
44
+ * Optimized the performance of `Delay`
45
+ - Fixed a bug in which no executor option on construction caused block execution on a global thread pool
46
+ * Numerous improvements and bug fixes to `TimerSet`
47
+ * Fixed deadlock of `Future` when the handler raises Exception
48
+ * Added shared specs for more classes
49
+ * New concurrency abstractions including:
50
+ - `Atom`
51
+ - `Maybe`
52
+ - `ImmutableStruct`
53
+ - `MutableStruct`
54
+ - `SettableStruct`
55
+ * Created an Edge gem for unstable abstractions including
56
+ - `Actor`
57
+ - `Agent`
58
+ - `Channel`
59
+ - `Exchanger`
60
+ - `LazyRegister`
61
+ - **new Future Framework** <http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge.html> - unified
62
+ implementation of Futures and Promises which combines Features of previous `Future`,
63
+ `Promise`, `IVar`, `Event`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively
64
+ new synchronization layer to make all the paths **lock-free** with exception of blocking threads on `#wait`.
65
+ It offers better performance and does not block threads when not required.
66
+ * Actor framework changes:
67
+ - fixed reset loop in Pool
68
+ - Pool can use any actor as a worker, abstract worker class is no longer needed.
69
+ - Actor events not have format `[:event_name, *payload]` instead of just the Symbol.
70
+ - Actor now uses new Future/Promise Framework instead of `IVar` for better interoperability
71
+ - Behaviour definition array was simplified to `[BehaviourClass1, [BehaviourClass2, *initialization_args]]`
72
+ - Linking behavior responds to :linked message by returning array of linked actors
73
+ - Supervised behavior is removed in favour of just Linking
74
+ - RestartingContext is supervised by default now, `supervise: true` is not required any more
75
+ - Events can be private and public, so far only difference is that Linking will
76
+ pass to linked actors only public messages. Adding private :restarting and
77
+ :resetting events which are send before the actor restarts or resets allowing
78
+ to add callbacks to cleanup current child actors.
79
+ - Print also object_id in Reference to_s
80
+ - Add AbstractContext#default_executor to be able to override executor class wide
81
+ - Add basic IO example
82
+ - Documentation somewhat improved
83
+ - All messages should have same priority. It's now possible to send `actor << job1 << job2 << :terminate!` and
84
+ be sure that both jobs are processed first.
85
+ * Refactored `Channel` to use newer synchronization objects
86
+ * Added `#reset` and `#cancel` methods to `TimerSet`
87
+ * Added `#cancel` method to `Future` and `ScheduledTask`
88
+ * Refactored `TimerSet` to use `ScheduledTask`
89
+ * Updated `Async` with a factory that initializes the object
90
+ * Deprecated `Concurrent.timer` and `Concurrent.timeout`
91
+ * Reduced max threads on pure-Ruby thread pools (abends around 14751 threads)
92
+ * Moved many private/internal classes/modules into "namespace" modules
93
+ * Removed brute-force killing of threads in tests
94
+ * Fixed a thread pool bug when the operating system cannot allocate more threads
95
+
96
+ ## Current Release v0.8.0 (25 January 2015)
2
97
 
3
98
  * C extension for MRI have been extracted into the `concurrent-ruby-ext` companion gem.
4
99
  Please see the README for more detail.
5
100
  * Better variable isolation in `Promise` and `Future` via an `:args` option
6
101
  * Continued to update intermittently failing tests
7
102
 
8
- ## Current Release v0.7.2 (24 January 2015)
103
+ ### Release v0.7.2 (24 January 2015)
9
104
 
10
105
  * New `Semaphore` class based on [java.util.concurrent.Semaphore](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html)
11
106
  * New `Promise.all?` and `Promise.any?` class methods
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Concurrent Ruby
2
- [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](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://img.shields.io/coveralls/ruby-concurrency/concurrent-ruby/master.svg)](https://coveralls.io/r/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.svg)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.svg)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.svg)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) [![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby)
2
+ [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](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) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.svg)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.svg)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.svg)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) [![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby)
3
3
 
4
4
  <table>
5
5
  <tr>
@@ -50,52 +50,91 @@ We also have a [mailing list](http://groups.google.com/group/concurrent-ruby).
50
50
 
51
51
  This library contains a variety of concurrency abstractions at high and low levels. One of the high-level abstractions is likely to meet most common needs.
52
52
 
53
- ### High-level, general-purpose asynchronous concurrency abstractions
53
+ #### General-purpose Concurrency Abstractions
54
54
 
55
- * [Actor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor.html): Implements the Actor Model, where concurrent actors exchange messages.
56
- * [Agent](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Agent.html): A single atomic value that represents an identity.
57
55
  * [Async](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Async.html): A mixin module that provides simple asynchronous behavior to any standard class/object or object.
56
+ * [Atom](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Atom.html): A way to manage shared, synchronous, independent state.
58
57
  * [Future](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Future.html): An asynchronous operation that produces a value.
59
- * [Dataflow](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Dataflow.html): Built on Futures, Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available.
58
+ * [Dataflow](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#dataflow-class_method): Built on Futures, Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available.
60
59
  * [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features.
61
60
  * [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html): Like a Future scheduled for a specific future time.
62
61
  * [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals.
63
- * [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html): Communicating Sequential Processes (CSP).
64
62
 
65
- ### Java-inspired ThreadPools and other executors
63
+ #### Thread-safe Value Objects
66
64
 
67
- * See [ThreadPool](http://ruby-concurrency.github.io/concurrent-ruby/file.thread_pools.html) overview, which also contains a list of other Executors available.
65
+ * `Maybe` A thread-safe, immutable object representing an optional value, based on
66
+ [Haskell Data.Maybe](https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html).
67
+ * `Delay` Lazy evaluation of a block yielding an immutable result. Based on Clojure's
68
+ [delay](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Delay.html).
68
69
 
69
- ### Thread-safe Observers
70
+ #### Thread-safe Structures
70
71
 
71
- * [Concurrent::Observable](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Observable.html) mixin module
72
- * [CopyOnNotifyObserverSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CopyOnNotifyObserverSet.html)
73
- * [CopyOnWriteObserverSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CopyOnWriteObserverSet.html)
72
+ Derived from Ruby's [Struct](http://ruby-doc.org/core-2.2.0/Struct.html):
74
73
 
75
- ### Thread synchronization classes and algorithms
74
+ * `ImmutableStruct` Immutable struct where values are set at construction and cannot be changed later.
75
+ * `MutableStruct` Synchronized, mutable struct where values can be safely changed at any time.
76
+ * `SettableStruct` Synchronized, write-once struct where values can be set at most once, either at construction or any time thereafter.
76
77
 
77
- Lower-level abstractions mainly used as building blocks.
78
+ #### Java-inspired ThreadPools and Other Executors
78
79
 
79
- * [condition](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Condition.html)
80
- * [countdown latch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html)
81
- * [cyclic barrier](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CyclicBarrier.html)
82
- * [event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html)
83
- * [exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html)
84
- * [semaphore](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Semaphore.html)
85
- * [timeout](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#timeout-class_method)
86
- * [timer](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#timer-class_method)
80
+ * See [ThreadPool](http://ruby-concurrency.github.io/concurrent-ruby/file.thread_pools.html) overview, which also contains a list of other Executors available.
87
81
 
88
- ### Thread-safe variables
82
+ #### Thread Synchronization Classes and Algorithms
89
83
 
90
- Lower-level abstractions mainly used as building blocks.
84
+ * [CountdownLatch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html)
85
+ * [CyclicBarrier](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CyclicBarrier.html)
86
+ * [Event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html)
87
+ * [Semaphore](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Semaphore.html)
88
+
89
+ #### Thread-safe Variables
91
90
 
92
91
  * [AtomicBoolean](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicBoolean.html)
93
92
  * [AtomicFixnum](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicFixnum.html)
94
- * AtomicReference (no docs currently available, check source)
93
+ * [AtomicReference](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MutexAtomic.html)
95
94
  * [I-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/IVar.html) (IVar)
96
95
  * [M-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MVar.html) (MVar)
97
- * [thread-local variables](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html)
98
- * [software transactional memory](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) (TVar)
96
+ * [Thread-local variables](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html)
97
+ * [Software transactional memory](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) (TVar)
98
+ * [ReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ReadWriteLock.html)
99
+
100
+ ### Edge Features
101
+
102
+ These are available in the `concurrent-ruby-edge` companion gem, installed with `gem install concurrent-ruby-edge`.
103
+
104
+ These features are under active development and may change frequently. They are expected not to
105
+ keep backward compatibility (there may also lack tests and documentation). Semantic versions will
106
+ be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to `concurrent-ruby` when final.
107
+
108
+ * [Actor](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor.html):
109
+ Implements the Actor Model, where concurrent actors exchange messages.
110
+ * [new Future Framework](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge.html) - new
111
+ unified implementation of Futures and Promises which combines Features of previous `Future`,
112
+ `Promise`, `IVar`, `Event`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively
113
+ new synchronization layer to make all the paths **lock-free** with exception of blocking threads on `#wait`.
114
+ It offers better performance and does not block threads when not required.
115
+ * [Agent](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Agent.html): A single atomic value that represents an identity.
116
+ * [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html):
117
+ Communicating Sequential Processes (CSP).
118
+ * [Exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html)
119
+ * [LazyRegister](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/LazyRegister.html)
120
+ * [New Future Promise Framework](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Edge.html) - new
121
+ unified implementation of Futures and Promises which combines Features of previous `Future`,
122
+ `Promise`, `IVar`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively
123
+ new synchronization layer to make all the paths lock-free with exception of blocking threads on `#wait`.
124
+ It offers better performance and does not block threads (exception being `#wait` and similar methods where it's
125
+ intended).
126
+
127
+
128
+ #### Statuses:
129
+
130
+ *Why is not in core?*
131
+
132
+ - **Actor** - partial documentation and tests, stability good.
133
+ - **Future/Promise Framework** - partial documentation and tests, stability good.
134
+ - **Agent** - incomplete behaviour compared to Clojure's model, stability good.
135
+ - **Channel** - missing documentation, stability good.
136
+ - **Exchanger** - known race issue.
137
+ - **LazyRegister** - missing documentation and tests.
99
138
 
100
139
  ## Usage
101
140
 
@@ -112,29 +151,39 @@ require 'concurrent' # everything
112
151
 
113
152
  # groups
114
153
 
115
- require 'concurrent/actor' # Concurrent::Actor and supporting code
116
154
  require 'concurrent/atomics' # atomic and thread synchronization classes
117
- require 'concurrent/channels' # Concurrent::Channel and supporting code
118
155
  require 'concurrent/executors' # Thread pools and other executors
119
- require 'concurrent/utilities' # utility methods such as processor count and timers
120
156
 
121
157
  # individual abstractions
122
158
 
159
+ require 'concurrent/async' # Concurrent::Async
160
+ require 'concurrent/atom' # Concurrent::Atom
161
+ require 'concurrent/dataflow' # Concurrent::dataflow
162
+ require 'concurrent/delay' # Concurrent::Delay
163
+ require 'concurrent/future' # Concurrent::Future
164
+ require 'concurrent/immutable_struct' # Concurrent::ImmutableStruct
165
+ require 'concurrent/ivar' # Concurrent::IVar
166
+ require 'concurrent/maybe' # Concurrent::Maybe
167
+ require 'concurrent/mutable_struct' # Concurrent::MutableStruct
168
+ require 'concurrent/mvar' # Concurrent::MVar
169
+ require 'concurrent/promise' # Concurrent::Promise
170
+ require 'concurrent/scheduled_task' # Concurrent::ScheduledTask
171
+ require 'concurrent/settable_struct' # Concurrent::SettableStruct
172
+ require 'concurrent/timer_task' # Concurrent::TimerTask
173
+ require 'concurrent/tvar' # Concurrent::TVar
174
+
175
+ # experimental - available in `concurrent-ruby-edge` companion gem
176
+
177
+ require 'concurrent/actor' # Concurrent::Actor and supporting code
178
+ require 'concurrent/edge/future' # new Future Framework
123
179
  require 'concurrent/agent' # Concurrent::Agent
124
- require 'concurrent/async' # Concurrent::Async
125
- require 'concurrent/atomic' # Concurrent::Atomic (formerly the `atomic` gem)
126
- require 'concurrent/dataflow' # Concurrent::dataflow
127
- require 'concurrent/delay' # Concurrent::Delay
180
+ require 'concurrent/channel ' # Concurrent::Channel and supporting code
128
181
  require 'concurrent/exchanger' # Concurrent::Exchanger
129
- require 'concurrent/future' # Concurrent::Future
130
- require 'concurrent/ivar' # Concurrent::IVar
131
- require 'concurrent/mvar' # Concurrent::MVar
132
- require 'concurrent/promise' # Concurrent::Promise
133
- require 'concurrent/scheduled_task' # Concurrent::ScheduledTask
134
- require 'concurrent/timer_task' # Concurrent::TimerTask
135
- require 'concurrent/tvar' # Concurrent::TVar
182
+ require 'concurrent/lazy_register' # Concurrent::LazyRegister
136
183
  ```
137
184
 
185
+ If the library does not behave as expected, `Concurrent.use_stdlib_logger(Logger::DEBUG)` could help to reveal the problem.
186
+
138
187
  ## Installation
139
188
 
140
189
  ```shell
@@ -153,8 +202,8 @@ and run `bundle install` from your shell.
153
202
 
154
203
  Potential performance improvements may be achieved under MRI by installing optional C extensions.
155
204
  To minimize installation errors the C extensions are available in the `concurrent-ruby-ext` extension
156
- gem. The extension gem lists `concurrent-ruby` as a dependency so it is not necessary to install both.
157
- Simply install the extension gen:
205
+ gem. `concurrent-ruby` and `concurrent-ruby-ext` are always released together with same version.
206
+ Simply install the extension gem too:
158
207
 
159
208
  ```ruby
160
209
  gem install concurrent-ruby-ext
@@ -191,22 +240,22 @@ any platform. *Documentation is forthcoming...*
191
240
 
192
241
  ```
193
242
  *MRI only*
194
- rake build:native # Build concurrent-ruby-ext-<version>-<platform>.gem into the pkg directory
195
- rake compile:extension # Compile extension
243
+ bundle exec rake build:native # Build concurrent-ruby-ext-<version>-<platform>.gem into the pkg dir
244
+ bundle exec rake compile:extension # Compile extension
196
245
 
197
246
  *JRuby only*
198
- rake build # Build JRuby-specific core gem (alias for `build:core`)
199
- rake build:core # Build concurrent-ruby-<version>-java.gem into the pkg directory
247
+ bundle exec rake build # Build JRuby-specific core gem (alias for `build:core`)
248
+ bundle exec rake build:core # Build concurrent-ruby-<version>-java.gem into the pkg directory
200
249
 
201
250
  *All except JRuby*
202
- rake build # Build core and extension gems
203
- rake build:core # Build concurrent-ruby-<version>.gem into the pkg directory
204
- rake build:ext # Build concurrent-ruby-ext-<version>.gem into the pkg directory
251
+ bundle exec rake build # Build core and extension gems
252
+ bundle exec rake build:core # Build concurrent-ruby-<version>.gem into the pkg directory
253
+ bundle exec rake build:ext # Build concurrent-ruby-ext-<version>.gem into the pkg directory
205
254
 
206
255
  *All*
207
- rake clean # Remove any temporary products
208
- rake clobber # Remove any generated file
209
- rake compile # Compile all the extensions
256
+ bundle exec rake clean # Remove any temporary products
257
+ bundle exec rake clobber # Remove any generated file
258
+ bundle exec rake compile # Compile all the extensions
210
259
  ```
211
260
 
212
261
  ## Maintainers
@@ -218,7 +267,7 @@ rake compile # Compile all the extensions
218
267
  * [Petr Chalupa](https://github.com/pitr-ch)
219
268
  * [Paweł Obrok](https://github.com/obrok)
220
269
 
221
- ### Contributing
270
+ ## Contributing
222
271
 
223
272
  1. Fork it
224
273
  2. Create your feature branch (`git checkout -b my-new-feature`)
data/lib/concurrent.rb CHANGED
@@ -1,39 +1,59 @@
1
1
  require 'concurrent/version'
2
2
 
3
+ require 'concurrent/synchronization'
4
+
3
5
  require 'concurrent/configuration'
4
6
 
5
7
  require 'concurrent/atomics'
6
- require 'concurrent/channels'
7
- require 'concurrent/collections'
8
+ require 'concurrent/errors'
8
9
  require 'concurrent/executors'
9
10
  require 'concurrent/utilities'
10
11
 
11
- require 'concurrent/actor'
12
- require 'concurrent/atomic'
13
- require 'concurrent/lazy_register'
14
- require 'concurrent/agent'
12
+ require 'concurrent/atomic/atomic_reference'
13
+ require 'concurrent/atom'
15
14
  require 'concurrent/async'
16
15
  require 'concurrent/dataflow'
17
16
  require 'concurrent/delay'
18
- require 'concurrent/dereferenceable'
19
- require 'concurrent/errors'
20
- require 'concurrent/exchanger'
21
17
  require 'concurrent/future'
18
+ require 'concurrent/immutable_struct'
22
19
  require 'concurrent/ivar'
20
+ require 'concurrent/maybe'
21
+ require 'concurrent/mutable_struct'
23
22
  require 'concurrent/mvar'
24
- require 'concurrent/obligation'
25
- require 'concurrent/observable'
26
- require 'concurrent/options_parser'
27
23
  require 'concurrent/promise'
28
24
  require 'concurrent/scheduled_task'
25
+ require 'concurrent/settable_struct'
29
26
  require 'concurrent/timer_task'
30
27
  require 'concurrent/tvar'
31
28
 
29
+ # @!macro [new] internal_implementation_note
30
+ #
31
+ # @note **Private Implementation:** This abstraction is a private, internal
32
+ # implementation detail. It should never be used directly.
33
+
34
+ # @!macro [new] monotonic_clock_warning
35
+ #
36
+ # @note Time calculations one all platforms and languages are sensitive to
37
+ # changes to the system clock. To alleviate the potential problems
38
+ # associated with changing the system clock while an application is running,
39
+ # most modern operating systems provide a monotonic clock that operates
40
+ # independently of the system clock. A monotonic clock cannot be used to
41
+ # determine human-friendly clock times. A monotonic clock is used exclusively
42
+ # for calculating time intervals. Not all Ruby platforms provide access to an
43
+ # operating system monotonic clock. On these platforms a pure-Ruby monotonic
44
+ # clock will be used as a fallback. An operating system monotonic clock is both
45
+ # faster and more reliable than the pure-Ruby implementation. The pure-Ruby
46
+ # implementation should be fast and reliable enough for most non-realtime
47
+ # operations. At this time the common Ruby platforms that provide access to an
48
+ # operating system monotonic clock are MRI 2.1 and above and JRuby (all versions).
49
+ #
50
+ # @see http://linux.die.net/man/3/clock_gettime Linux clock_gettime(3)
51
+
32
52
  # Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
33
53
  # F#, C#, Java, and classic concurrency patterns.
34
- #
54
+ #
35
55
  # The design goals of this gem are:
36
- #
56
+ #
37
57
  # * Stay true to the spirit of the languages providing inspiration
38
58
  # * But implement in a way that makes sense for Ruby
39
59
  # * Keep the semantics as idiomatic Ruby as possible
@@ -8,13 +8,92 @@ require 'concurrent/executor/serialized_execution'
8
8
 
9
9
  module Concurrent
10
10
 
11
- # {include:file:doc/async.md}
11
+ # A mixin module that provides simple asynchronous behavior to any standard
12
+ # class/object or object.
13
+ #
14
+ # ```cucumber
15
+ # Feature:
16
+ # As a stateful, plain old Ruby class/object
17
+ # I want safe, asynchronous behavior
18
+ # So my long-running methods don't block the main thread
19
+ # ```
20
+ #
21
+ # Stateful, mutable objects must be managed carefully when used asynchronously.
22
+ # But Ruby is an object-oriented language so designing with objects and classes
23
+ # plays to Ruby's strengths and is often more natural to many Ruby programmers.
24
+ # The `Async` module is a way to mix simple yet powerful asynchronous capabilities
25
+ # into any plain old Ruby object or class. These capabilities provide a reasonable
26
+ # level of thread safe guarantees when used correctly.
27
+ #
28
+ # When this module is mixed into a class or object it provides to new methods:
29
+ # `async` and `await`. These methods are thread safe with respect to the enclosing
30
+ # object. The former method allows methods to be called asynchronously by posting
31
+ # to the global thread pool. The latter allows a method to be called synchronously
32
+ # on the current thread but does so safely with respect to any pending asynchronous
33
+ # method calls. Both methods return an `Obligation` which can be inspected for
34
+ # the result of the method call. Calling a method with `async` will return a
35
+ # `:pending` `Obligation` whereas `await` will return a `:complete` `Obligation`.
36
+ #
37
+ # Very loosely based on the `async` and `await` keywords in C#.
38
+ #
39
+ # ### An Important Note About Initialization
40
+ #
41
+ # > This module depends on several internal stnchronization mechanisms that
42
+ # > must be initialized prior to calling any of the async/await/executor methods.
43
+ # > To ensure thread-safe initialization the class `new` method will be made
44
+ # > private when the `Concurrent::Async` module is included. A factory method
45
+ # > called `create` will be defined in its place. The `create`factory will
46
+ # > create a new object instance, passing all arguments to the constructor,
47
+ # > and will initialize all stnchronization mechanisms. This is the only way
48
+ # > thread-safe initialization can be guaranteed.
49
+ #
50
+ # ### An Important Note About Thread Safe Guarantees
51
+ #
52
+ # > Thread safe guarantees can only be made when asynchronous method calls
53
+ # > are not mixed with synchronous method calls. Use only synchronous calls
54
+ # > when the object is used exclusively on a single thread. Use only
55
+ # > `async` and `await` when the object is shared between threads. Once you
56
+ # > call a method using `async`, you should no longer call any methods
57
+ # > directly on the object. Use `async` and `await` exclusively from then on.
58
+ # > With careful programming it is possible to switch back and forth but it's
59
+ # > also very easy to create race conditions and break your application.
60
+ # > Basically, it's "async all the way down."
61
+ #
62
+ # @example
63
+ #
64
+ # class Echo
65
+ # include Concurrent::Async
66
+ #
67
+ # def echo(msg)
68
+ # sleep(rand)
69
+ # print "#{msg}\n"
70
+ # nil
71
+ # end
72
+ # end
12
73
  #
13
- # @since 0.6.0
74
+ # horn = Echo.new #=> NoMethodError: private method `new' called for Echo:Class
75
+ #
76
+ # horn = Echo.create
77
+ # horn.echo('zero') # synchronous, not thread-safe
78
+ #
79
+ # horn.async.echo('one') # asynchronous, non-blocking, thread-safe
80
+ # horn.await.echo('two') # synchronous, blocking, thread-safe
14
81
  #
15
- # @see Concurrent::Obligation
82
+ # @see Concurrent::Concern::Obligation
83
+ # @see Concurrent::IVar
16
84
  module Async
17
85
 
86
+ # @!method self.create(*args, &block)
87
+ #
88
+ # The factory method used to create new instances of the asynchronous
89
+ # class. Used instead of `new` to ensure proper initialization of the
90
+ # synchronization mechanisms.
91
+ #
92
+ # @param [Array<Object>] args Zero or more arguments to be passed to the
93
+ # object's initializer.
94
+ # @param [Proc] bloc Optional block to pass to the object's initializer.
95
+ # @return [Object] A properly initialized object of the asynchronous class.
96
+
18
97
  # Check for the presence of a method on an object and determine if a given
19
98
  # set of arguments matches the required arity.
20
99
  #
@@ -34,7 +113,9 @@ module Concurrent
34
113
  # @see http://www.ruby-doc.org/core-2.1.1/Method.html#method-i-arity Method#arity
35
114
  # @see http://ruby-doc.org/core-2.1.0/Object.html#method-i-respond_to-3F Object#respond_to?
36
115
  # @see http://www.ruby-doc.org/core-2.1.0/BasicObject.html#method-i-method_missing BasicObject#method_missing
37
- def validate_argc(obj, method, *args)
116
+ #
117
+ # @!visibility private
118
+ def self.validate_argc(obj, method, *args)
38
119
  argc = args.length
39
120
  arity = obj.method(method).arity
40
121
 
@@ -44,12 +125,36 @@ module Concurrent
44
125
  raise ArgumentError.new("wrong number of arguments (#{argc} for #{arity}..*)")
45
126
  end
46
127
  end
47
- module_function :validate_argc
128
+
129
+ # @!visibility private
130
+ def self.included(base)
131
+ base.singleton_class.send(:alias_method, :original_new, :new)
132
+ base.send(:private_class_method, :original_new)
133
+ base.extend(ClassMethods)
134
+ super(base)
135
+ end
136
+
137
+ # @!visibility private
138
+ module ClassMethods
139
+
140
+ # @deprecated
141
+ def new(*args, &block)
142
+ warn '[DEPRECATED] use the `create` method instead'
143
+ create(*args, &block)
144
+ end
145
+
146
+ def create(*args, &block)
147
+ obj = original_new(*args, &block)
148
+ obj.send(:init_synchronization)
149
+ obj
150
+ end
151
+ end
152
+ private_constant :ClassMethods
48
153
 
49
154
  # Delegates asynchronous, thread-safe method calls to the wrapped object.
50
155
  #
51
156
  # @!visibility private
52
- class AsyncDelegator # :nodoc:
157
+ class AsyncDelegator
53
158
 
54
159
  # Create a new delegator object wrapping the given delegate,
55
160
  # protecting it with the given serializer, and executing it on the
@@ -84,14 +189,11 @@ module Concurrent
84
189
  self.define_singleton_method(method) do |*args2|
85
190
  Async::validate_argc(@delegate, method, *args2)
86
191
  ivar = Concurrent::IVar.new
87
- value, reason = nil, nil
88
192
  @serializer.post(@executor.value) do
89
193
  begin
90
- value = @delegate.send(method, *args2, &block)
194
+ ivar.set(@delegate.send(method, *args2, &block))
91
195
  rescue => reason
92
- # caught
93
- ensure
94
- ivar.complete(reason.nil?, value, reason)
196
+ ivar.fail(reason)
95
197
  end
96
198
  end
97
199
  ivar.value if @blocking
@@ -101,6 +203,7 @@ module Concurrent
101
203
  self.send(method, *args)
102
204
  end
103
205
  end
206
+ private_constant :AsyncDelegator
104
207
 
105
208
  # Causes the chained method call to be performed asynchronously on the
106
209
  # global thread pool. The method called by this method will return a
@@ -115,26 +218,24 @@ module Concurrent
115
218
  # library, some edge cases will be missed. For more information see
116
219
  # the documentation for the `validate_argc` method.
117
220
  #
118
- # @note The method call is guaranteed to be thread safe with respect to
119
- # all other method calls against the same object that are called with
120
- # either `async` or `await`. The mutable nature of Ruby references
121
- # (and object orientation in general) prevent any other thread safety
122
- # guarantees. Do NOT mix non-protected method calls with protected
123
- # method call. Use *only* protected method calls when sharing the object
124
- # between threads.
221
+ # @!macro [attach] async_thread_safety_warning
222
+ # @note The method call is guaranteed to be thread safe with respect to
223
+ # all other method calls against the same object that are called with
224
+ # either `async` or `await`. The mutable nature of Ruby references
225
+ # (and object orientation in general) prevent any other thread safety
226
+ # guarantees. Do NOT mix non-protected method calls with protected
227
+ # method call. Use *only* protected method calls when sharing the object
228
+ # between threads.
125
229
  #
126
230
  # @return [Concurrent::IVar] the pending result of the asynchronous operation
127
231
  #
128
- # @raise [Concurrent::InitializationError] `#init_mutex` has not been called
129
232
  # @raise [NameError] the object does not respond to `method` method
130
233
  # @raise [ArgumentError] the given `args` do not match the arity of `method`
131
234
  #
132
235
  # @see Concurrent::IVar
133
236
  def async
134
- raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
135
237
  @__async_delegator__.value
136
238
  end
137
- alias_method :future, :async
138
239
 
139
240
  # Causes the chained method call to be performed synchronously on the
140
241
  # current thread. The method called by this method will return an
@@ -149,58 +250,71 @@ module Concurrent
149
250
  # library, some edge cases will be missed. For more information see
150
251
  # the documentation for the `validate_argc` method.
151
252
  #
152
- # @note The method call is guaranteed to be thread safe with respect to
153
- # all other method calls against the same object that are called with
154
- # either `async` or `await`. The mutable nature of Ruby references
155
- # (and object orientation in general) prevent any other thread safety
156
- # guarantees. Do NOT mix non-protected method calls with protected
157
- # method call. Use *only* protected method calls when sharing the object
158
- # between threads.
253
+ # @!macro async_thread_safety_warning
159
254
  #
160
255
  # @return [Concurrent::IVar] the completed result of the synchronous operation
161
256
  #
162
- # @raise [Concurrent::InitializationError] `#init_mutex` has not been called
163
257
  # @raise [NameError] the object does not respond to `method` method
164
258
  # @raise [ArgumentError] the given `args` do not match the arity of `method`
165
259
  #
166
260
  # @see Concurrent::IVar
167
261
  def await
168
- raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
169
262
  @__await_delegator__.value
170
263
  end
171
- alias_method :delay, :await
172
264
 
173
- # Set a new executor
265
+ # Set a new executor.
174
266
  #
175
- # @raise [Concurrent::InitializationError] `#init_mutex` has not been called
176
- # @raise [ArgumentError] executor has already been set
267
+ # @raise [ArgumentError] executor has already been set.
177
268
  def executor=(executor)
178
- raise InitializationError.new('#init_mutex was never called') unless @__async_initialized__
179
269
  @__async_executor__.reconfigure { executor } or
180
270
  raise ArgumentError.new('executor has already been set')
181
271
  end
182
272
 
183
- # Initialize the internal serializer and other synchronization objects. This method
184
- # *must* be called from the constructor of the including class or explicitly
185
- # by the caller prior to calling any other methods. If `init_mutex` is *not*
186
- # called explicitly the async/await/executor methods will raize a
187
- # `Concurrent::InitializationError`. This is the only way thread-safe
188
- # initialization can be guaranteed.
273
+ # Initialize the internal serializer and other stnchronization mechanisms.
189
274
  #
190
- # @note This method *must* be called from the constructor of the including
191
- # class or explicitly by the caller prior to calling any other methods.
192
- # This is the only way thread-safe initialization can be guaranteed.
275
+ # @note This method *must* be called immediately upon object construction.
276
+ # This is the only way thread-safe initialization can be guaranteed.
193
277
  #
194
278
  # @raise [Concurrent::InitializationError] when called more than once
279
+ #
280
+ # @!visibility private
281
+ # @deprecated
195
282
  def init_mutex
196
- raise InitializationError.new('#init_mutex was already called') if @__async_initialized__
283
+ warn '[DEPRECATED] use the `create` method instead'
284
+ init_synchronization
285
+ rescue InitializationError
286
+ # suppress
287
+ end
288
+
289
+ private
290
+
291
+ # Initialize the internal serializer and other stnchronization mechanisms.
292
+ #
293
+ # @note This method *must* be called immediately upon object construction.
294
+ # This is the only way thread-safe initialization can be guaranteed.
295
+ #
296
+ # @raise [Concurrent::InitializationError] when called more than once
297
+ #
298
+ # @!visibility private
299
+ def init_synchronization
300
+ return self if @__async_initialized__
301
+
197
302
  @__async_initialized__ = true
198
303
  serializer = Concurrent::SerializedExecution.new
199
- @__async_executor__ = Delay.new{ Concurrent.configuration.global_operation_pool }
200
- @__await_delegator__ = Delay.new{ AsyncDelegator.new(
201
- self, Delay.new{ Concurrent::ImmediateExecutor.new }, serializer, true) }
202
- @__async_delegator__ = Delay.new{ AsyncDelegator.new(
203
- self, @__async_executor__, serializer, false) }
304
+
305
+ @__async_executor__ = Delay.new {
306
+ Concurrent.global_io_executor
307
+ }
308
+
309
+ @__await_delegator__ = Delay.new {
310
+ AsyncDelegator.new(self, Delay.new{ Concurrent::ImmediateExecutor.new }, serializer, true)
311
+ }
312
+
313
+ @__async_delegator__ = Delay.new {
314
+ AsyncDelegator.new(self, @__async_executor__, serializer, false)
315
+ }
316
+
317
+ self
204
318
  end
205
319
  end
206
320
  end