concurrent-ruby 0.7.0.rc2-x64-mingw32 → 0.7.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZWMzOTY0NWI3OTIzNTkwNTFmMjU5MzcxZmMzMjI0YTViZDA5OGI4NQ==
4
+ ZTI4NDQyMTI4NjE0MDIwYTQ4ZWI2NjQ0YTg4MTZlY2UzZGMyMjVkZQ==
5
5
  data.tar.gz: !binary |-
6
- ZGY1YzlhYzJhMmE4NzAyZmJkNDdmNDU1OTE4ODJjM2I5NDdmMGQwYg==
6
+ NDk4YzIwZjAxYzhiZjgxNGJkODQwNGM5OThlZTAzNTI5Mzc1MmJiMw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MmNhNmQwODRkMWNmNmY2MmNjNWE2YzA1NDcxYzFlYjIzNjQ0YTY1NjRjODhi
10
- MjE0NTRhYmI4YWRhYjQwMjFlNDc5YWJlMjk4YmRlYjk5YjU5NDkwN2RjYzBj
11
- N2JiYjRhYjdhODA5MjEwZTUzMzQyN2FiZjExNjFlYmE1MTRjYzU=
9
+ MmM3ZGM4MmEyOGUyNGJhOTdjZDA0YjBiNzI1NmRjNjViYTY5M2ZhNzAyMzQy
10
+ ZjMyODAwYjIzZmU4MWQ4NzUyOWJjZDYyNDE3MDBhMTJjY2ZlODQzODM3NjNl
11
+ NzVjMmZlM2Q2Mjg0MjdhYjVjMTcxYzMxN2MyOTdlMzQ5Y2I0ZmU=
12
12
  data.tar.gz: !binary |-
13
- MTQ4ODQ0YzE3Mjg1OTU1ZjY2MjcxNzlmYTMxOTNmNmEyNjY2NmFjMzliZTk2
14
- OGZiMzY3MDkzNzRmYjk4Njc4YmNiN2MzNTNjOGI2NjBhZmE3YTU2MzMxNDlm
15
- MDcyNjM0YTdmMzZmNmMyODE4NDFkOTgyN2M2MTNlYTU2MmJmNDQ=
13
+ YmUyOTUyMjMyOTJhMzkwYjdkZDJhMzcyODk1ZmE0MmNmYWY0NzAwYzBlZGY4
14
+ MWYxOGMxMmE4NTNjYzg2NzNkYjI2NjNiOGIzMDk4MjRkMmZhYzAzZDJjZWY4
15
+ NGE0OGNjZmNlZGQxOTExNWU2ZDZjM2FkNzU2OGRlNWNlMzIzYjI=
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Concurrent Ruby
2
- [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.png)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Coverage Status](https://coveralls.io/repos/ruby-concurrency/concurrent-ruby/badge.png)](https://coveralls.io/r/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.png)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.png)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.png)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![Gitter chat](https://badges.gitter.im/ruby-concurrency/concurrent-ruby.png)](https://gitter.im/ruby-concurrency/concurrent-ruby)
2
+ [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.png)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Coverage Status](https://coveralls.io/repos/ruby-concurrency/concurrent-ruby/badge.png)](https://coveralls.io/r/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.png)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.png)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.png)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![License](http://img.shields.io/license/MIT.png?color=green)](http://opensource.org/licenses/MIT) [![Gitter chat](https://badges.gitter.im/ruby-concurrency/concurrent-ruby.png)](https://gitter.im/ruby-concurrency/concurrent-ruby)
3
3
 
4
4
  <table>
5
5
  <tr>
@@ -35,22 +35,6 @@
35
35
  </tr>
36
36
  </table>
37
37
 
38
- ## Install
39
-
40
- ```shell
41
- gem install concurrent-ruby
42
- ```
43
-
44
- or add the following line to Gemfile:
45
-
46
- ```ruby
47
- gem 'concurrent-ruby'
48
- ```
49
-
50
- and run `bundle install` from your shell.
51
-
52
- _NOTE: There is an old gem from 2007 called "concurrent" that does not appear to be under active development. That isn't us. Please do not run* `gem install concurrent`*. It is not the droid you are looking for._
53
-
54
38
  ## Features & Documentation
55
39
 
56
40
  Please see the [Concurrent Ruby Wiki](https://github.com/ruby-concurrency/concurrent-ruby/wiki)
@@ -61,21 +45,27 @@ There are many concurrency abstractions in this library. These abstractions can
61
45
  into several general groups:
62
46
 
63
47
  * Asynchronous concurrency abstractions including
64
- [Async](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Async),
65
- [Agent](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Agent),
66
- [Future](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Future),
67
- [Promise](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Promise),
68
- [ScheduledTask](https://github.com/ruby-concurrency/concurrent-ruby/wiki/ScheduledTask),
69
- and [TimerTask](https://github.com/ruby-concurrency/concurrent-ruby/wiki/TimerTask)
70
- * Thread-safe variables including [M-Structures](https://github.com/ruby-concurrency/concurrent-ruby/wiki/MVar-(M-Structure)),
71
- [I-Structures](https://github.com/ruby-concurrency/concurrent-ruby/wiki/IVar-(I-Structure)),
72
- [thread-local variables](https://github.com/ruby-concurrency/concurrent-ruby/wiki/ThreadLocalVar),
73
- atomic counters, and [software transactional memory](https://github.com/ruby-concurrency/concurrent-ruby/wiki/TVar-(STM))
74
- * Thread synchronization classes and algorithms including [dataflow](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Dataflow),
75
- timeout, condition, countdown latch, dependency counter, and event
76
- * Java-inspired [thread pools](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Thread%20Pools)
77
- * New fast light-weighted [Actor model](http://ruby-concurrency.github.io/concurrent-ruby/frames.html#!Concurrent/Actress.html) implementation.
78
- * And many more...
48
+ [Agent](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Agent.html),
49
+ [Async](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Async.html),
50
+ [Future](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Future.html),
51
+ [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html),
52
+ [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html),
53
+ and [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html)
54
+ * Fast, light-weight [Actor model](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Actor.html) implementation.
55
+ * Thread-safe variables including
56
+ [I-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/IVar.html),
57
+ [M-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MVar.html),
58
+ [thread-local variables](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html),
59
+ and [software transactional memory](https://github.com/ruby-concurrency/concurrent-ruby/wiki/TVar-(STM))
60
+ * Thread synchronization classes and algorithms including
61
+ [condition](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Condition.html),
62
+ [countdown latch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html),
63
+ [dataflow](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Dataflow),
64
+ [event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html),
65
+ [exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html),
66
+ and [timeout](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#timeout-class_method)
67
+ * Java-inspired [executors](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Thread%20Pools) (thread pools and more)
68
+ * [And many more](http://ruby-concurrency.github.io/concurrent-ruby/index.html)...
79
69
 
80
70
  ### Semantic Versioning
81
71
 
@@ -90,7 +80,8 @@ It should be fully compatible with any interpreter that is compliant with Ruby 1
90
80
  ### Examples
91
81
 
92
82
  Many more code examples can be found in the documentation for each class (linked above).
93
- This one simple example shows some of the power of this gem.
83
+
84
+ Future and ScheduledTask:
94
85
 
95
86
  ```ruby
96
87
  require 'concurrent'
@@ -112,18 +103,6 @@ sleep(1) # do other stuff
112
103
  price.value #=> 63.65
113
104
  price.state #=> :fulfilled
114
105
 
115
- # Promise
116
- prices = Concurrent::Promise.new{ puts Ticker.new.get_year_end_closing('AAPL', 2013) }.
117
- then{ puts Ticker.new.get_year_end_closing('MSFT', 2013) }.
118
- then{ puts Ticker.new.get_year_end_closing('GOOG', 2013) }.
119
- then{ puts Ticker.new.get_year_end_closing('AMZN', 2013) }.execute
120
- prices.state #=> :pending
121
- sleep(1) # do other stuff
122
- #=> 561.02
123
- #=> 37.41
124
- #=> 1120.71
125
- #=> 398.79
126
-
127
106
  # ScheduledTask
128
107
  task = Concurrent::ScheduledTask.execute(2){ Ticker.new.get_year_end_closing('INTC', 2013) }
129
108
  task.state #=> :pending
@@ -131,6 +110,88 @@ sleep(3) # do other stuff
131
110
  task.value #=> 25.96
132
111
  ```
133
112
 
113
+ Actor:
114
+
115
+ ```ruby
116
+ class Counter < Concurrent::Actor::Context
117
+ # Include context of an actor which gives this class access to reference
118
+ # and other information about the actor
119
+
120
+ # use initialize as you wish
121
+ def initialize(initial_value)
122
+ @count = initial_value
123
+ end
124
+
125
+ # override on_message to define actor's behaviour
126
+ def on_message(message)
127
+ if Integer === message
128
+ @count += message
129
+ end
130
+ end
131
+ end #
132
+
133
+ # Create new actor naming the instance 'first'.
134
+ # Return value is a reference to the actor, the actual actor is never returned.
135
+ counter = Counter.spawn(:first, 5)
136
+
137
+ # Tell a message and forget returning self.
138
+ counter.tell(1)
139
+ counter << 1
140
+ # (First counter now contains 7.)
141
+
142
+ # Send a messages asking for a result.
143
+ counter.ask(0).class
144
+ counter.ask(0).value
145
+ ```
146
+
147
+ ## Installing and Building
148
+
149
+ This gem includes several platform-specific optimizations. To reduce the possibility of
150
+ compilation errors, we provide pre-compiled gem packages for several platforms as well
151
+ as a pure-Ruby build. Installing the gem should be no different than installing any other
152
+ Rubygems-hosted gem.
153
+
154
+ ### Installing
155
+
156
+ ```shell
157
+ gem install concurrent-ruby
158
+ ```
159
+
160
+ or add the following line to Gemfile:
161
+
162
+ ```ruby
163
+ gem 'concurrent-ruby'
164
+ ```
165
+
166
+ and run `bundle install` from your shell.
167
+
168
+ ### Building
169
+
170
+ Because we provide pre-compiled gem builds, users should never need to build the gem manually.
171
+ The build process for this gem is completely automated using open source tools. All of
172
+ the automation components are available in the [ruby-concurrency/rake-compiler-dev-box](https://github.com/ruby-concurrency/rake-compiler-dev-box)
173
+ GitHub repository.
174
+
175
+ This gem will compile native C code under MRI and native Java code under JRuby. It is
176
+ also possible to build a pure-Ruby version. All builds have identical functionality.
177
+ The only difference is performance. Additionally, pure-Ruby classes are always available,
178
+ even when using the native optimizations. Please see the [documentation](http://ruby-concurrency.github.io/concurrent-ruby/)
179
+ for more details.
180
+
181
+ To build and package the gem using MRI or JRuby, install the necessary build dependencies and run:
182
+
183
+ ```shell
184
+ bundle exec rake compile
185
+ bundle exec rake build
186
+ ```
187
+
188
+ To build and package a pure-Ruby gem, on *any* platform and interpreter
189
+ (including MRI and JRuby), run:
190
+
191
+ ```shell
192
+ BUILD_PURE_RUBY='true' bundle exec rake build
193
+ ```
194
+
134
195
  ## Maintainers
135
196
 
136
197
  * [Jerry D'Antonio](https://github.com/jdantonio)
@@ -139,22 +200,6 @@ task.value #=> 25.96
139
200
  * [Lucas Allan](https://github.com/lucasallan)
140
201
  * [Petr Chalupa](https://github.com/pitr-ch)
141
202
 
142
- ### Contributors
143
-
144
- * [Bill Dueber](https://github.com/billdueber)
145
- * [Brian Shirai](https://github.com/brixen)
146
- * [Chip Miller](https://github.com/chip-miller)
147
- * [Giuseppe Capizzi](https://github.com/gcapizzi)
148
- * [Jamie Hodge](https://github.com/jamiehodge)
149
- * [Justin Lambert](https://github.com/mastfish)
150
- * [Larry Lv](https://github.com/larrylv)
151
- * [Maxim Chechel](https://github.com/maximchick)
152
- * [Ravil Bayramgalin](https://github.com/brainopia)
153
- * [René Föhring](https://github.com/rrrene)
154
- * [Shane Wilton](https://github.com/ShaneWilton)
155
- * [sheaney](https://github.com/sheaney)
156
- * [Zander Hill](https://github.com/zph)
157
-
158
203
  ### Contributing
159
204
 
160
205
  1. Fork it
@@ -27,18 +27,31 @@ VALUE ir_initialize(int argc, VALUE* argv, VALUE self) {
27
27
  }
28
28
 
29
29
  VALUE ir_get(VALUE self) {
30
+ #if HAVE_GCC_SYNC
31
+ __sync_synchronize();
32
+ #elif defined _MSC_VER
33
+ MemoryBarrier();
34
+ #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
35
+ OSMemoryBarrier();
36
+ #endif
30
37
  return (VALUE) DATA_PTR(self);
31
38
  }
32
39
 
33
40
  VALUE ir_set(VALUE self, VALUE new_value) {
34
41
  DATA_PTR(self) = (void *) new_value;
42
+ #if HAVE_GCC_SYNC
43
+ __sync_synchronize();
44
+ #elif defined _MSC_VER
45
+ MemoryBarrier();
46
+ #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
47
+ OSMemoryBarrier();
48
+ #endif
35
49
  return new_value;
36
50
  }
37
51
 
38
52
  VALUE ir_get_and_set(VALUE self, VALUE new_value) {
39
- VALUE old_value;
40
- old_value = (VALUE) DATA_PTR(self);
41
- DATA_PTR(self) = (void *) new_value;
53
+ VALUE old_value = ir_get(self);
54
+ ir_set(self, new_value);
42
55
  return old_value;
43
56
  }
44
57
 
@@ -12,7 +12,7 @@ def create_dummy_makefile
12
12
  end
13
13
  end
14
14
 
15
- if defined?(JRUBY_VERSION) || ! Concurrent.use_c_extensions?
15
+ if defined?(JRUBY_VERSION) || ! Concurrent.allow_c_extensions?
16
16
  create_dummy_makefile
17
17
  warn 'C optimizations are not supported on this version of Ruby.'
18
18
  else
@@ -43,12 +43,11 @@ else
43
43
  end
44
44
  end
45
45
 
46
- try_run(<<CODE,$CFLAGS) && ($defs << '-DHAVE_GCC_CAS')
47
- int main() {
48
- int i = 1;
49
- __sync_bool_compare_and_swap(&i, 1, 4);
50
- return (i != 4);
51
- }
46
+ try_run(<<CODE,$CFLAGS) && ($defs << '-DHAVE_GCC_SYNC')
47
+ int main() {
48
+ __sync_synchronize();
49
+ return 0;
50
+ }
52
51
  CODE
53
52
 
54
53
  create_makefile(EXTENSION_NAME)
@@ -26,7 +26,7 @@ module Concurrent
26
26
 
27
27
  require 'concurrent/actor/default_dead_letter_handler'
28
28
  require 'concurrent/actor/root'
29
- require 'concurrent/actor/ad_hoc'
29
+ require 'concurrent/actor/utils'
30
30
 
31
31
  # @return [Reference, nil] current executing actor if any
32
32
  def self.current
@@ -1,7 +1,7 @@
1
1
  module Concurrent
2
2
  module Actor
3
3
  module Behaviour
4
- # Delegates messages nad events to {AbstractContext} instance
4
+ # Delegates messages and events to {AbstractContext} instance
5
5
  class ExecutesContext < Abstract
6
6
  def on_envelope(envelope)
7
7
  context.on_envelope envelope
@@ -2,7 +2,7 @@ module Concurrent
2
2
  module Actor
3
3
  module Behaviour
4
4
 
5
- # Sets nad holds the supervisor of the actor if any. There is only one or none supervisor
5
+ # Sets and holds the supervisor of the actor if any. There is at most one supervisor
6
6
  # for each actor. Each supervisor is automatically linked.
7
7
  class Supervised < Abstract
8
8
  attr_reader :supervisor
@@ -4,7 +4,7 @@ module Concurrent
4
4
  # Terminates all children when the actor terminates.
5
5
  class TerminatesChildren < Abstract
6
6
  def on_event(event)
7
- children.each { |ch| ch << :terminate! } if event == :terminated
7
+ children.map { |ch| ch.ask :terminate! }.each(&:wait) if event == :terminated
8
8
  super event
9
9
  end
10
10
  end
@@ -37,7 +37,7 @@ module Concurrent
37
37
  # @option opts [true, false] link, atomically link the actor to its parent
38
38
  # @option opts [true, false] supervise, atomically supervise the actor by its parent
39
39
  # @option opts [Array<Array(Behavior::Abstract, Array<Object>)>] behaviour_definition, array of pairs
40
- # where each pair is behaviour class and its args, see {Behaviour.basic_behaviour}
40
+ # where each pair is behaviour class and its args, see {Behaviour.basic_behaviour_definition}
41
41
  # @option opts [IVar, nil] initialized, if present it'll be set or failed after {Context} initialization
42
42
  # @option opts [Proc, nil] logger a proc accepting (level, progname, message = nil, &block) params,
43
43
  # can be used to hook actor instance to any logging system
@@ -0,0 +1,10 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Utils
4
+ require 'concurrent/actor/utils/ad_hoc'
5
+ require 'concurrent/actor/utils/broadcast'
6
+ require 'concurrent/actor/utils/balancer'
7
+ require 'concurrent/actor/utils/pool'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Utils
4
+ # Allows quick creation of actors with behaviour defined by blocks.
5
+ # @example ping
6
+ # AdHoc.spawn :forward, an_actor do |where|
7
+ # # this block has to return proc defining #on_message behaviour
8
+ # -> message { where.tell message }
9
+ # end
10
+ class AdHoc < Context
11
+ def initialize(*args, &initializer)
12
+ @on_message = Type! initializer.call(*args), Proc
13
+ end
14
+
15
+ def on_message(message)
16
+ instance_exec message, &@on_message
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Utils
4
+
5
+ # Distributes messages between subscribed actors. Each actor'll get only one message then
6
+ # it's unsubscribed. The actor needs to resubscribe when it's ready to receive next message.
7
+ # @see Pool
8
+ class Balancer < RestartingContext
9
+
10
+ def initialize
11
+ @receivers = []
12
+ @buffer = []
13
+ end
14
+
15
+ def on_message(message)
16
+ case message
17
+ when :subscribe
18
+ @receivers << envelope.sender
19
+ distribute
20
+ true
21
+ when :unsubscribe
22
+ @receivers.delete envelope.sender
23
+ true
24
+ when :subscribed?
25
+ @receivers.include? envelope.sender
26
+ else
27
+ @buffer << message
28
+ distribute
29
+ end
30
+ end
31
+
32
+ def distribute
33
+ while !@receivers.empty? && !@buffer.empty?
34
+ @receivers.shift << @buffer.shift
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -4,8 +4,20 @@ module Concurrent
4
4
  module Actor
5
5
  module Utils
6
6
 
7
- # TODO doc
8
- class Broadcast < Context
7
+ # Allows to build pub/sub easily.
8
+ # @example news
9
+ # news_channel = Concurrent::Actor::Utils::Broadcast.spawn :news
10
+ #
11
+ # 2.times do |i|
12
+ # Concurrent::Actor::Utils::AdHoc.spawn "listener-#{i}" do
13
+ # news_channel << :subscribe
14
+ # -> message { puts message }
15
+ # end
16
+ # end
17
+ #
18
+ # news_channel << 'Ruby rocks!'
19
+ # # prints: 'Ruby rocks!' twice
20
+ class Broadcast < RestartingContext
9
21
 
10
22
  def initialize
11
23
  @receivers = Set.new
@@ -14,11 +26,14 @@ module Concurrent
14
26
  def on_message(message)
15
27
  case message
16
28
  when :subscribe
17
- @receivers.add envelope.sender
18
- true
29
+ if envelope.sender.is_a? Reference
30
+ @receivers.add envelope.sender
31
+ true
32
+ else
33
+ false
34
+ end
19
35
  when :unsubscribe
20
- @receivers.delete envelope.sender
21
- true
36
+ !!@receivers.delete(envelope.sender)
22
37
  when :subscribed?
23
38
  @receivers.include? envelope.sender
24
39
  else
@@ -31,6 +46,7 @@ module Concurrent
31
46
  @receivers
32
47
  end
33
48
  end
49
+
34
50
  end
35
51
  end
36
52
  end
@@ -0,0 +1,59 @@
1
+ require 'concurrent/actor/utils/balancer'
2
+
3
+ module Concurrent
4
+ module Actor
5
+ module Utils
6
+
7
+ # Allows to create a pool of workers and distribute work between them
8
+ # @param [Integer] size number of workers
9
+ # @yield [balancer, index] a block spawning an worker instance. called +size+ times.
10
+ # The worker should be descendant of AbstractWorker and supervised, see example.
11
+ # @yieldparam [Balancer] balancer to pass to the worker
12
+ # @yieldparam [Integer] index of the worker, usually used in its name
13
+ # @yieldreturn [Reference] the reference of newly created worker
14
+ # @example
15
+ # class Worker < Concurrent::Actor::Utils::AbstractWorker
16
+ # def work(message)
17
+ # p message * 5
18
+ # end
19
+ # end
20
+ #
21
+ # pool = Concurrent::Actor::Utils::Pool.spawn! 'pool', 5 do |balancer, index|
22
+ # Worker.spawn name: "worker-#{index}", supervise: true, args: [balancer]
23
+ # end
24
+ #
25
+ # pool << 'asd' << 2
26
+ # # prints:
27
+ # # "asdasdasdasdasd"
28
+ # # 10
29
+ class Pool < RestartingContext
30
+ def initialize(size, &worker_initializer)
31
+ @balancer = Balancer.spawn name: :balancer, supervise: true
32
+ @workers = Array.new(size, &worker_initializer.curry[@balancer])
33
+ @workers.each { |w| Type! w, Reference }
34
+ end
35
+
36
+ def on_message(message)
37
+ @balancer << message
38
+ end
39
+ end
40
+
41
+ class AbstractWorker < RestartingContext
42
+ def initialize(balancer)
43
+ @balancer = balancer
44
+ @balancer << :subscribe
45
+ end
46
+
47
+ def on_message(message)
48
+ work message
49
+ ensure
50
+ @balancer << :subscribe
51
+ end
52
+
53
+ def work(message)
54
+ raise NotImplementedError
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,3 +1,17 @@
1
+ #####################################################################
2
+ # Attempt to check for the deprecated ruby-atomic gem and warn the
3
+ # user that they should use the new implementation instead.
4
+
5
+ if defined?(Atomic)
6
+ warn <<-RUBY
7
+ [ATOMIC] Detected an `Atomic` class, which may indicate a dependency
8
+ on the ruby-atomic gem. That gem has been deprecated and merged into
9
+ the concurrent-ruby gem. Please use the Concurrent::Atomic class for
10
+ atomic references and not the Atomic class.
11
+ RUBY
12
+ end
13
+ #####################################################################
14
+
1
15
  require 'concurrent/atomic_reference/concurrent_update_error'
2
16
  require 'concurrent/atomic_reference/mutex_atomic'
3
17
 
@@ -57,41 +71,21 @@ if defined? Concurrent::JavaAtomic
57
71
  class Concurrent::Atomic < Concurrent::JavaAtomic
58
72
  end
59
73
 
60
- elsif defined? Concurrent::CAtomic
61
-
62
- # @!macro [attach] concurrent_update_error
63
- #
64
- # This exception may be thrown by methods that have detected concurrent
65
- # modification of an object when such modification is not permissible.
66
- class Concurrent::Atomic < Concurrent::CAtomic
67
- end
68
-
69
74
  elsif defined? Concurrent::RbxAtomic
70
75
 
71
76
  # @!macro atomic_reference
72
77
  class Concurrent::Atomic < Concurrent::RbxAtomic
73
78
  end
74
79
 
75
- else
80
+ elsif Concurrent.allow_c_native_class?('CAtomic')
76
81
 
77
82
  # @!macro atomic_reference
78
- class Concurrent::Atomic < Concurrent::MutexAtomic
83
+ class Concurrent::Atomic < Concurrent::CAtomic
79
84
  end
80
- end
81
85
 
82
- # @!macro atomic_reference
83
- class Atomic < Concurrent::Atomic
84
-
85
- # @!macro concurrent_update_error
86
- ConcurrentUpdateError = Class.new(Concurrent::ConcurrentUpdateError)
86
+ else
87
87
 
88
- # @!macro [attach] atomic_reference_method_initialize
89
- #
90
- # Creates a new Atomic reference with null initial value.
91
- #
92
- # @param [Object] value the initial value
93
- def initialize(value)
94
- warn "[DEPRECATED] Please use Concurrent::Atomic instead."
95
- super
88
+ # @!macro atomic_reference
89
+ class Concurrent::Atomic < Concurrent::MutexAtomic
96
90
  end
97
91
  end
@@ -1,3 +1,6 @@
1
+ require_relative '../../extension_helper'
2
+ Concurrent.safe_require_c_extensions
3
+
1
4
  module Concurrent
2
5
 
3
6
  # @!macro [attach] atomic_boolean
@@ -159,7 +162,7 @@ module Concurrent
159
162
  class AtomicBoolean < JavaAtomicBoolean
160
163
  end
161
164
 
162
- elsif defined? Concurrent::CAtomicBoolean
165
+ elsif Concurrent.allow_c_native_class?('CAtomicBoolean')
163
166
 
164
167
  # @!macro atomic_boolean
165
168
  class CAtomicBoolean
@@ -1,3 +1,6 @@
1
+ require_relative '../../extension_helper'
2
+ Concurrent.safe_require_c_extensions
3
+
1
4
  module Concurrent
2
5
 
3
6
  # @!macro [attach] atomic_fixnum
@@ -163,7 +166,7 @@ module Concurrent
163
166
  class AtomicFixnum < JavaAtomicFixnum
164
167
  end
165
168
 
166
- elsif defined? Concurrent::CAtomicFixnum
169
+ elsif Concurrent.allow_c_native_class?('CAtomicFixnum')
167
170
 
168
171
  # @!macro atomic_fixnum
169
172
  class CAtomicFixnum
@@ -1,10 +1,14 @@
1
- require 'concurrent_ruby_ext'
2
- require 'concurrent/atomic_reference/direct_update'
1
+ require_relative '../../extension_helper'
2
+ Concurrent.safe_require_java_extensions
3
3
 
4
- module Concurrent
4
+ if defined?(Concurrent::JavaAtomic)
5
+ require 'concurrent/atomic_reference/direct_update'
5
6
 
6
- # @!macro atomic_reference
7
- class JavaAtomic
8
- include Concurrent::AtomicDirectUpdate
7
+ module Concurrent
8
+
9
+ # @!macro atomic_reference
10
+ class JavaAtomic
11
+ include Concurrent::AtomicDirectUpdate
12
+ end
9
13
  end
10
14
  end
@@ -1,8 +1,12 @@
1
- begin
2
- require 'concurrent_ruby_ext'
3
- rescue LoadError
4
- # may be a Windows cross-compiled native gem
5
- require "#{RUBY_VERSION[0..2]}/concurrent_ruby_ext"
1
+ require_relative '../../extension_helper'
2
+
3
+ if Concurrent.allow_c_extensions?
4
+ begin
5
+ require 'concurrent_ruby_ext'
6
+ rescue LoadError
7
+ # may be a Windows cross-compiled native gem
8
+ require "#{RUBY_VERSION[0..2]}/concurrent_ruby_ext"
9
+ end
6
10
  end
7
11
 
8
12
  require 'concurrent/atomic_reference/direct_update'
@@ -14,19 +18,19 @@ module Concurrent
14
18
  class CAtomic
15
19
  include Concurrent::AtomicDirectUpdate
16
20
  include Concurrent::AtomicNumericCompareAndSetWrapper
17
-
21
+
18
22
  # @!method initialize
19
23
  # @!macro atomic_reference_method_initialize
20
-
24
+
21
25
  # @!method get
22
26
  # @!macro atomic_reference_method_get
23
-
27
+
24
28
  # @!method set
25
29
  # @!macro atomic_reference_method_set
26
-
30
+
27
31
  # @!method get_and_set
28
32
  # @!macro atomic_reference_method_get_and_set
29
-
33
+
30
34
  # @!method _compare_and_set
31
35
  # @!macro atomic_reference_method_compare_and_set
32
36
  end
@@ -1,12 +1,14 @@
1
1
  require 'delegate'
2
2
  require 'concurrent/executor/executor'
3
3
  require 'concurrent/logging'
4
+ require 'concurrent/atomic/synchronization'
4
5
 
5
6
  module Concurrent
6
7
 
7
8
  # Ensures passed jobs in a serialized order never running at the same time.
8
9
  class SerializedExecution
9
10
  include Logging
11
+ include Synchronization
10
12
 
11
13
  Job = Struct.new(:executor, :args, :block) do
12
14
  def call
@@ -15,9 +17,10 @@ module Concurrent
15
17
  end
16
18
 
17
19
  def initialize
18
- @being_executed = false
19
- @stash = []
20
- @mutex = Mutex.new
20
+ synchronize do
21
+ @being_executed = false
22
+ @stash = []
23
+ end
21
24
  end
22
25
 
23
26
  # Submit a task to the executor for asynchronous processing.
@@ -33,23 +36,36 @@ module Concurrent
33
36
  #
34
37
  # @raise [ArgumentError] if no task is given
35
38
  def post(executor, *args, &task)
36
- return nil if task.nil?
37
-
38
- job = Job.new executor, args, task
39
-
40
- begin
41
- @mutex.lock
42
- post = if @being_executed
43
- @stash << job
44
- false
45
- else
46
- @being_executed = true
47
- end
48
- ensure
49
- @mutex.unlock
39
+ posts [[executor, args, task]]
40
+ true
41
+ end
42
+
43
+ # As {#post} but allows to submit multiple tasks at once, it's guaranteed that they will not
44
+ # be interleaved by other tasks.
45
+ #
46
+ # @param [Array<Array(Executor, Array<Object>, Proc)>] posts array of triplets where
47
+ # first is a {Executor}, second is array of args for task, third is a task (Proc)
48
+ def posts(posts)
49
+ # if can_overflow?
50
+ # raise ArgumentError, 'SerializedExecution does not support thread-pools which can overflow'
51
+ # end
52
+
53
+ return nil if posts.empty?
54
+
55
+ jobs = posts.map { |executor, args, task| Job.new executor, args, task }
56
+
57
+ job_to_post = synchronize do
58
+ if @being_executed
59
+ @stash.push(*jobs)
60
+ nil
61
+ else
62
+ @being_executed = true
63
+ @stash.push(*jobs[1..-1])
64
+ jobs.first
65
+ end
50
66
  end
51
67
 
52
- call_job job if post
68
+ call_job job_to_post if job_to_post
53
69
  true
54
70
  end
55
71
 
@@ -78,11 +94,8 @@ module Concurrent
78
94
  def work(job)
79
95
  job.call
80
96
  ensure
81
- begin
82
- @mutex.lock
97
+ synchronize do
83
98
  job = @stash.shift || (@being_executed = false)
84
- ensure
85
- @mutex.unlock
86
99
  end
87
100
 
88
101
  call_job job if job
@@ -98,7 +111,7 @@ module Concurrent
98
111
  include SerialExecutor
99
112
 
100
113
  def initialize(executor)
101
- @executor = executor
114
+ @executor = executor
102
115
  @serializer = SerializedExecution.new
103
116
  super(executor)
104
117
  end
@@ -112,7 +112,7 @@ module Concurrent
112
112
  result = Transaction::ABORTED
113
113
  rescue => e
114
114
  transaction.abort
115
- throw e
115
+ raise e
116
116
  end
117
117
  # If we can commit, break out of the loop
118
118
 
@@ -1,3 +1,3 @@
1
1
  module Concurrent
2
- VERSION = '0.7.0.rc2'
2
+ VERSION = '0.7.0'
3
3
  end
Binary file
@@ -1,9 +1,28 @@
1
- require 'rbconfig'
2
-
3
1
  module Concurrent
4
- def self.use_c_extensions?
5
- host_os = RbConfig::CONFIG['host_os']
6
- ruby_name = RbConfig::CONFIG['ruby_install_name']
7
- (ruby_name =~ /^ruby$/i || host_os =~ /mswin32/i || host_os =~ /mingw32/i)
2
+
3
+ # @!visibility private
4
+ def self.allow_c_extensions?
5
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
6
+ end
7
+
8
+ # @!visibility private
9
+ def self.allow_c_native_class?(clazz)
10
+ allow_c_extensions? && Concurrent.const_defined?(clazz)
11
+ rescue
12
+ false
13
+ end
14
+
15
+ # @!visibility private
16
+ def self.safe_require_c_extensions
17
+ require 'concurrent_ruby_ext' if allow_c_extensions?
18
+ rescue LoadError
19
+ #warn 'Attempted to load C extensions on unsupported platform. Continuing with pure-Ruby.'
20
+ end
21
+
22
+ # @!visibility private
23
+ def self.safe_require_java_extensions
24
+ require 'concurrent_ruby_ext' if RUBY_PLATFORM == 'java'
25
+ rescue LoadError
26
+ #warn 'Attempted to load Java extensions on unsupported platform. Continuing with pure-Ruby.'
8
27
  end
9
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.rc2
4
+ version: 0.7.0
5
5
  platform: x64-mingw32
6
6
  authors:
7
7
  - Jerry D'Antonio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-30 00:00:00.000000000 Z
11
+ date: 2014-08-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: ! " Modern concurrency tools including agents, futures, promises,
14
14
  thread pools, actors, supervisors, and more.\n Inspired by Erlang, Clojure, Go,
@@ -34,7 +34,6 @@ files:
34
34
  - lib/2.0/concurrent_ruby_ext.so
35
35
  - lib/concurrent.rb
36
36
  - lib/concurrent/actor.rb
37
- - lib/concurrent/actor/ad_hoc.rb
38
37
  - lib/concurrent/actor/behaviour.rb
39
38
  - lib/concurrent/actor/behaviour/abstract.rb
40
39
  - lib/concurrent/actor/behaviour/awaits.rb
@@ -59,8 +58,11 @@ files:
59
58
  - lib/concurrent/actor/reference.rb
60
59
  - lib/concurrent/actor/root.rb
61
60
  - lib/concurrent/actor/type_check.rb
62
- - lib/concurrent/actor/utills.rb
61
+ - lib/concurrent/actor/utils.rb
62
+ - lib/concurrent/actor/utils/ad_hoc.rb
63
+ - lib/concurrent/actor/utils/balancer.rb
63
64
  - lib/concurrent/actor/utils/broadcast.rb
65
+ - lib/concurrent/actor/utils/pool.rb
64
66
  - lib/concurrent/actress.rb
65
67
  - lib/concurrent/agent.rb
66
68
  - lib/concurrent/async.rb
@@ -153,9 +155,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
153
155
  version: 1.9.3
154
156
  required_rubygems_version: !ruby/object:Gem::Requirement
155
157
  requirements:
156
- - - ! '>'
158
+ - - ! '>='
157
159
  - !ruby/object:Gem::Version
158
- version: 1.3.1
160
+ version: '0'
159
161
  requirements: []
160
162
  rubyforge_project:
161
163
  rubygems_version: 2.2.2
@@ -1,19 +0,0 @@
1
- module Concurrent
2
- module Actor
3
- # Allows quick creation of actors with behaviour defined by blocks.
4
- # @example ping
5
- # AdHoc.spawn :forward, an_actor do |where|
6
- # # this block has to return proc defining #on_message behaviour
7
- # -> message { where.tell message }
8
- # end
9
- class AdHoc < Context
10
- def initialize(*args, &initializer)
11
- @on_message = Type! initializer.call(*args), Proc
12
- end
13
-
14
- def on_message(message)
15
- instance_exec message, &@on_message
16
- end
17
- end
18
- end
19
- end
@@ -1,7 +0,0 @@
1
- module Concurrent
2
- module Actor
3
- module Utils
4
- require 'concurrent/actor/utils/broadcast'
5
- end
6
- end
7
- end