Skip to content
Permalink
Browse files

Bump version, update doc

  • Loading branch information...
pitr-ch committed Mar 9, 2019
1 parent d84d13e commit 3ff1cb09c0a34e2dba46f970398ad0d659cbe42e
Showing with 2,276 additions and 227 deletions.
  1. +13 −0 CHANGELOG.md
  2. +1 −1 Gemfile
  3. +3 −0 README.md
  4. +1 −0 Rakefile
  5. +69 −66 docs-source/channel.out.md
  6. +273 −0 docs-source/medium-example.in.rb
  7. +13 −0 docs-source/medium-example.init.rb
  8. +707 −0 docs-source/medium-example.out.rb
  9. +208 −0 docs-source/ruby-association-final-report.md
  10. +1 −1 docs-source/ruby-association-intermediate-report.md
  11. +16 −7 docs/master/Concurrent.html
  12. +24 −24 docs/master/Concurrent/ErlangActor/Down.html
  13. +26 −23 docs/master/Concurrent/ErlangActor/Environment.html
  14. +8 −8 docs/master/Concurrent/ErlangActor/EnvironmentConstants/AbstractLogicOperationMatcher.html
  15. +4 −4 docs/master/Concurrent/ErlangActor/EnvironmentConstants/And.html
  16. +4 −4 docs/master/Concurrent/ErlangActor/EnvironmentConstants/Or.html
  17. +8 −8 docs/master/Concurrent/ErlangActor/FunctionShortcuts.html
  18. +18 −18 docs/master/Concurrent/ErlangActor/Functions.html
  19. +17 −17 docs/master/Concurrent/ErlangActor/NoActor.html
  20. +20 −20 docs/master/Concurrent/ErlangActor/Terminated.html
  21. +4 −4 docs/master/Concurrent/LockFreeStack.html
  22. +14 −14 docs/master/Concurrent/Promises/Channel.html
  23. +5 −2 docs/master/_index.html
  24. +17 −0 docs/master/file.CHANGELOG.html
  25. +3 −0 docs/master/file.README.html
  26. +782 −0 docs/master/file.medium-example.out.html
  27. +7 −2 docs/master/file_list.html
  28. +3 −0 docs/master/index.html
  29. +5 −2 lib-edge/concurrent/edge/erlang_actor.rb
  30. +1 −1 lib/concurrent/collection/lock_free_stack.rb
  31. +1 −1 lib/concurrent/version.rb
@@ -1,5 +1,18 @@
## Current

## Release v1.1.5, edge v0.5.0 (10 mar 2019)

concurrent-ruby:

* fix potential leak of context on JRuby and Java 7

concurrent-ruby-edge:

* Add finalized Concurrent::Cancellation
* Add finalized Concurrent::Throttle
* Add finalized Concurrent::Promises::Channel
* Add new Concurrent::ErlangActor

## Release v1.1.4 (14 Dec 2018)

* (#780) Remove java_alias of 'submit' method of Runnable to let executor service work on java 11
@@ -20,7 +20,7 @@ end
group :documentation, optional: true do
gem 'yard', '~> 0.9.0', require: false
gem 'redcarpet', '~> 3.0', platforms: :mri # understands github markdown
gem 'md-ruby-eval', '~> 0.4'
gem 'md-ruby-eval', '~> 0.6'
end

group :testing do
@@ -367,6 +367,9 @@ and to the past maintainers
* [Paweł Obrok](https://github.com/obrok)
* [Lucas Allan](https://github.com/lucasallan)

and to [Ruby Association](https://www.ruby.or.jp/en/) for sponsoring a project
["Enhancing Ruby’s concurrency tooling"](https://www.ruby.or.jp/en/news/20181106) in 2018.

## License and Copyright

*Concurrent Ruby* is free software released under the
@@ -171,6 +171,7 @@ begin
'-',
'docs-source/thread_pools.md',
'docs-source/promises.out.md',
'docs-source/medium-example.out.rb',
'LICENSE.md',
'CHANGELOG.md']
end
@@ -16,14 +16,14 @@ threads = Array.new(3) { |i| Thread.new { ch.push message: i } }
sleep 0.01 # let the threads run
threads
# => [#<Thread:0x000003@channel.in.md:14 dead>,
# #<Thread:0x000004@channel.in.md:14 sleep_forever>,
# #<Thread:0x000005@channel.in.md:14 dead>]
# #<Thread:0x000004@channel.in.md:14 dead>,
# #<Thread:0x000005@channel.in.md:14 sleep_forever>]
```

When message is popped the last thread continues and finishes as well.

```ruby
ch.pop # => {:message=>2}
ch.pop # => {:message=>0}
threads.map(&:join)
# => [#<Thread:0x000003@channel.in.md:14 dead>,
# #<Thread:0x000004@channel.in.md:14 dead>,
@@ -38,11 +38,14 @@ one will be blocked until new messages is pushed.
```ruby
threads = Array.new(3) { |i| Thread.new { ch.pop } }
sleep 0.01 # let the threads run
threads.map(&:status) # => [false, false, "sleep"]
threads
# => [#<Thread:0x000006@channel.in.md:32 dead>,
# #<Thread:0x000007@channel.in.md:32 dead>,
# #<Thread:0x000008@channel.in.md:32 sleep_forever>]
ch.push message: 3
# => #<Concurrent::Promises::Channel:0x000002 capacity taken 0 of 2>
threads.map(&:value)
# => [{:message=>0}, {:message=>1}, {:message=>3}]
# => [{:message=>1}, {:message=>2}, {:message=>3}]
```

### Promises integration
@@ -52,11 +55,11 @@ therefore all operations can be represented as futures.

```ruby
ch = Concurrent::Promises::Channel.new 2
# => #<Concurrent::Promises::Channel:0x000006 capacity taken 0 of 2>
# => #<Concurrent::Promises::Channel:0x000009 capacity taken 0 of 2>
push_operations = Array.new(3) { |i| ch.push_op message: i }
# => [#<Concurrent::Promises::Future:0x000007 fulfilled with #<Concurrent::Promises::Channel:0x000006 capacity taken 2 of 2>>,
# #<Concurrent::Promises::Future:0x000008 fulfilled with #<Concurrent::Promises::Channel:0x000006 capacity taken 2 of 2>>,
# #<Concurrent::Promises::ResolvableFuture:0x000009 pending>]
# => [#<Concurrent::Promises::Future:0x00000a fulfilled with #<Concurrent::Promises::Channel:0x000009 capacity taken 2 of 2>>,
# #<Concurrent::Promises::Future:0x00000b fulfilled with #<Concurrent::Promises::Channel:0x000009 capacity taken 2 of 2>>,
# #<Concurrent::Promises::ResolvableFuture:0x00000c pending>]
```

> We do not have to sleep here letting the futures execute as Threads.
@@ -70,14 +73,14 @@ making a space for a new message.
```ruby
ch.pop_op.value! # => {:message=>0}
push_operations.map(&:value!)
# => [#<Concurrent::Promises::Channel:0x000006 capacity taken 2 of 2>,
# #<Concurrent::Promises::Channel:0x000006 capacity taken 2 of 2>,
# #<Concurrent::Promises::Channel:0x000006 capacity taken 2 of 2>]
# => [#<Concurrent::Promises::Channel:0x000009 capacity taken 2 of 2>,
# #<Concurrent::Promises::Channel:0x000009 capacity taken 2 of 2>,
# #<Concurrent::Promises::Channel:0x000009 capacity taken 2 of 2>]
pop_operations = Array.new(3) { |i| ch.pop_op }
# => [#<Concurrent::Promises::ResolvableFuture:0x00000a fulfilled with {:message=>1}>,
# #<Concurrent::Promises::ResolvableFuture:0x00000b fulfilled with {:message=>2}>,
# #<Concurrent::Promises::ResolvableFuture:0x00000c pending>]
# => [#<Concurrent::Promises::ResolvableFuture:0x00000d fulfilled with {:message=>1}>,
# #<Concurrent::Promises::ResolvableFuture:0x00000e fulfilled with {:message=>2}>,
# #<Concurrent::Promises::ResolvableFuture:0x00000f pending>]
ch.push message: 3 # (push|pop) can be freely mixed with (push_o|pop_op)
pop_operations.map(&:value)
# => [{:message=>1}, {:message=>2}, {:message=>3}]
@@ -91,21 +94,21 @@ returns a pair to be able to find out which channel had the message available.

```ruby
ch1 = Concurrent::Promises::Channel.new 2
# => #<Concurrent::Promises::Channel:0x00000d capacity taken 0 of 2>
# => #<Concurrent::Promises::Channel:0x000010 capacity taken 0 of 2>
ch2 = Concurrent::Promises::Channel.new 2
# => #<Concurrent::Promises::Channel:0x00000e capacity taken 0 of 2>
# => #<Concurrent::Promises::Channel:0x000011 capacity taken 0 of 2>
ch1.push 1
# => #<Concurrent::Promises::Channel:0x00000d capacity taken 1 of 2>
# => #<Concurrent::Promises::Channel:0x000010 capacity taken 1 of 2>
ch2.push 2
# => #<Concurrent::Promises::Channel:0x00000e capacity taken 1 of 2>
# => #<Concurrent::Promises::Channel:0x000011 capacity taken 1 of 2>
Concurrent::Promises::Channel.select([ch1, ch2])
# => [#<Concurrent::Promises::Channel:0x00000d capacity taken 0 of 2>, 1]
# => [#<Concurrent::Promises::Channel:0x000010 capacity taken 0 of 2>, 1]
ch1.select(ch2)
# => [#<Concurrent::Promises::Channel:0x00000e capacity taken 0 of 2>, 2]
# => [#<Concurrent::Promises::Channel:0x000011 capacity taken 0 of 2>, 2]
Concurrent::Promises.future { 3 + 4 }.then_channel_push(ch1)
# => #<Concurrent::Promises::Future:0x00000f pending>
# => #<Concurrent::Promises::Future:0x000012 pending>
Concurrent::Promises::Channel.
# or `ch1.select_op(ch2)` would be equivalent
select_op([ch1, ch2]).
@@ -122,7 +125,7 @@ They always return immediately and indicate either success or failure.

```ruby
ch
# => #<Concurrent::Promises::Channel:0x000006 capacity taken 0 of 2>
# => #<Concurrent::Promises::Channel:0x000009 capacity taken 0 of 2>
ch.try_push 1 # => true
ch.try_push 2 # => true
ch.try_push 3 # => false
@@ -139,7 +142,7 @@ when the timeout option is used.

```ruby
ch
# => #<Concurrent::Promises::Channel:0x000006 capacity taken 0 of 2>
# => #<Concurrent::Promises::Channel:0x000009 capacity taken 0 of 2>
ch.push 1, 0.01 # => true
ch.push 2, 0.01 # => true
ch.push 3, 0.01 # => false
@@ -156,7 +159,7 @@ if the consumers are not keeping up.

```ruby
channel = Concurrent::Promises::Channel.new 2
# => #<Concurrent::Promises::Channel:0x000010 capacity taken 0 of 2>
# => #<Concurrent::Promises::Channel:0x000013 capacity taken 0 of 2>
log = Concurrent::Array.new # => []
producers = Array.new 2 do |i|
@@ -167,8 +170,8 @@ producers = Array.new 2 do |i|
end
end
end
# => [#<Thread:0x000011@channel.in.md:133 run>,
# #<Thread:0x000012@channel.in.md:133 run>]
# => [#<Thread:0x000014@channel.in.md:133 run>,
# #<Thread:0x000015@channel.in.md:133 run>]
consumers = Array.new 4 do |i|
Thread.new(i) do |consumer|
@@ -180,38 +183,38 @@ consumers = Array.new 4 do |i|
end
end
end
# => [#<Thread:0x000013@channel.in.md:142 run>,
# #<Thread:0x000014@channel.in.md:142 run>,
# #<Thread:0x000015@channel.in.md:142 run>,
# #<Thread:0x000016@channel.in.md:142 run>]
# => [#<Thread:0x000016@channel.in.md:142 run>,
# #<Thread:0x000017@channel.in.md:142 run>,
# #<Thread:0x000018@channel.in.md:142 run>,
# #<Thread:0x000019@channel.in.md:142 run>]
# wait for all to finish
producers.map(&:join)
# => [#<Thread:0x000011@channel.in.md:133 dead>,
# #<Thread:0x000012@channel.in.md:133 dead>]
# => [#<Thread:0x000014@channel.in.md:133 dead>,
# #<Thread:0x000015@channel.in.md:133 dead>]
consumers.map(&:join)
# => [#<Thread:0x000013@channel.in.md:142 dead>,
# #<Thread:0x000014@channel.in.md:142 dead>,
# #<Thread:0x000015@channel.in.md:142 dead>,
# #<Thread:0x000016@channel.in.md:142 dead>]
# => [#<Thread:0x000016@channel.in.md:142 dead>,
# #<Thread:0x000017@channel.in.md:142 dead>,
# #<Thread:0x000018@channel.in.md:142 dead>,
# #<Thread:0x000019@channel.in.md:142 dead>]
# investigate log
log
log
# => ["producer 0 pushing 0",
# "producer 0 pushing 1",
# "producer 0 pushing 2",
# "producer 1 pushing 0",
# "consumer 0 got 0. payload 0 from producer 0",
# "producer 0 pushing 3",
# "consumer 2 got 0. payload 1 from producer 0",
# "consumer 1 got 0. payload 1 from producer 0",
# "producer 1 pushing 1",
# "consumer 1 got 0. payload 2 from producer 0",
# "consumer 3 got 0. payload 0 from producer 1",
# "consumer 3 got 0. payload 2 from producer 0",
# "producer 1 pushing 2",
# "consumer 2 got 1. payload 3 from producer 0",
# "consumer 0 got 1. payload 1 from producer 1",
# "consumer 3 got 1. payload 2 from producer 1",
# "consumer 2 got 0. payload 0 from producer 1",
# "producer 1 pushing 3",
# "consumer 1 got 1. payload 3 from producer 1"]
# "producer 0 pushing 3",
# "consumer 0 got 1. payload 1 from producer 1",
# "consumer 1 got 1. payload 2 from producer 1",
# "consumer 3 got 1. payload 3 from producer 1",
# "consumer 2 got 1. payload 3 from producer 0"]
```

The producers are much faster than consumers
@@ -226,7 +229,7 @@ that run a thread pool.

```ruby
channel = Concurrent::Promises::Channel.new 2
# => #<Concurrent::Promises::Channel:0x000017 capacity taken 0 of 2>
# => #<Concurrent::Promises::Channel:0x00001a capacity taken 0 of 2>
log = Concurrent::Array.new # => []
def produce(channel, log, producer, i)
@@ -248,38 +251,38 @@ end # => :consume
producers = Array.new 2 do |i|
Concurrent::Promises.future(channel, log, i) { |*args| produce *args, 0 }.run
end
# => [#<Concurrent::Promises::Future:0x000018 pending>,
# #<Concurrent::Promises::Future:0x000019 pending>]
# => [#<Concurrent::Promises::Future:0x00001b pending>,
# #<Concurrent::Promises::Future:0x00001c pending>]
consumers = Array.new 4 do |i|
Concurrent::Promises.future(channel, log, i) { |*args| consume *args, 0 }.run
end
# => [#<Concurrent::Promises::Future:0x00001a pending>,
# #<Concurrent::Promises::Future:0x00001b pending>,
# #<Concurrent::Promises::Future:0x00001c pending>,
# #<Concurrent::Promises::Future:0x00001d pending>]
# => [#<Concurrent::Promises::Future:0x00001d pending>,
# #<Concurrent::Promises::Future:0x00001e pending>,
# #<Concurrent::Promises::Future:0x00001f pending>,
# #<Concurrent::Promises::Future:0x000020 pending>]
# wait for all to finish
producers.map(&:value!) # => [:done, :done]
consumers.map(&:value!) # => [:done, :done, :done, :done]
# investigate log
log
log
# => ["producer 0 pushing 0",
# "producer 1 pushing 0",
# "consumer 1 got 0. payload 0 from producer 1",
# "producer 0 pushing 1",
# "producer 1 pushing 1",
# "consumer 0 got 0. payload 0 from producer 0",
# "consumer 3 got 0. payload 1 from producer 0",
# "consumer 1 got 0. payload 0 from producer 1",
# "consumer 2 got 0. payload 1 from producer 0",
# "producer 0 pushing 2",
# "consumer 3 got 0. payload 1 from producer 1",
# "producer 1 pushing 2",
# "producer 1 pushing 3",
# "producer 0 pushing 3",
# "consumer 2 got 0. payload 1 from producer 1",
# "consumer 0 got 1. payload 2 from producer 0",
# "consumer 2 got 1. payload 3 from producer 1",
# "consumer 1 got 1. payload 3 from producer 0",
# "consumer 3 got 1. payload 2 from producer 1"]
# "producer 1 pushing 3",
# "consumer 0 got 1. payload 2 from producer 1",
# "consumer 2 got 1. payload 3 from producer 0",
# "consumer 1 got 1. payload 2 from producer 0",
# "consumer 3 got 1. payload 3 from producer 1"]
```

### Synchronization of workers by passing a value
@@ -292,19 +295,19 @@ The operations have to be paired to succeed.

```ruby
channel = Concurrent::Promises::Channel.new 0
# => #<Concurrent::Promises::Channel:0x00001e capacity taken 0 of 0>
# => #<Concurrent::Promises::Channel:0x000021 capacity taken 0 of 0>
thread = Thread.new { channel.pop }; sleep 0.01
# allow the thread to go to sleep
thread
# => #<Thread:0x00001f@channel.in.md:246 sleep_forever>
# => #<Thread:0x000022@channel.in.md:214 sleep_forever>
# succeeds because there is matching pop operation waiting in the thread
channel.try_push(:v1) # => true
# remains pending, since there is no matching operation
push = channel.push_op(:v2)
# => #<Concurrent::Promises::ResolvableFuture:0x000020 pending>
# => #<Concurrent::Promises::ResolvableFuture:0x000023 pending>
thread.value # => :v1
# the push operation resolves as a pairing pop is called
channel.pop # => :v2
push
# => #<Concurrent::Promises::ResolvableFuture:0x000020 fulfilled with #<Concurrent::Promises::Channel:0x00001e capacity taken 0 of 0>>
# => #<Concurrent::Promises::ResolvableFuture:0x000023 fulfilled with #<Concurrent::Promises::Channel:0x000021 capacity taken 0 of 0>>
```
Oops, something went wrong.

0 comments on commit 3ff1cb0

Please sign in to comment.
You can’t perform that action at this time.