concurrent-ruby 0.8.0 → 0.9.0.pre2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
OSZAR »