vcap-concurrency 0.1.0

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.
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe VCAP::Concurrency::Proxy do
4
+ describe "#method_missing" do
5
+ it "should proxy method calls to the underlying object" do
6
+ proxied_object = ["hi"]
7
+ proxy = VCAP::Concurrency::Proxy.new(proxied_object)
8
+ proxy << "there"
9
+
10
+ proxied_object.should == ["hi", "there"]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ require "thread"
2
+
3
+ require "vcap/concurrency"
@@ -0,0 +1,175 @@
1
+ require "set"
2
+
3
+ require "spec_helper"
4
+
5
+ $stdout.sync = true
6
+
7
+ describe VCAP::Concurrency::ThreadPool do
8
+ describe "#start" do
9
+ it "should raise an error if it has already been started or stopped" do
10
+ tp = VCAP::Concurrency::ThreadPool.new(1)
11
+ tp.start
12
+
13
+ # Started
14
+ expect do
15
+ tp.start
16
+ end.to raise_error(/invalid state/i)
17
+
18
+ # Stopped
19
+ tp.stop
20
+ expect do
21
+ tp.start
22
+ end.to raise_error(/invalid state/i)
23
+ end
24
+
25
+ it "should start the requested number of worker threads" do
26
+ waiting = VCAP::Concurrency::AtomicVar.new(0)
27
+ barrier = Mutex.new
28
+ num_threads = 5
29
+ promises = []
30
+ tp = VCAP::Concurrency::ThreadPool.new(num_threads)
31
+
32
+ # Each worker notifies the main thread that it is ready. When all workers
33
+ # have checked in, the main thread unblocks them all.
34
+ num_threads.times do |ii|
35
+ promises << tp.enqueue do
36
+ waiting.mutate { |v| v + 1 }
37
+
38
+ barrier.synchronize {}
39
+
40
+ Thread.current
41
+ end
42
+ end
43
+
44
+ barrier.lock
45
+
46
+ tp.start
47
+
48
+ # Wait until all threads have checked in
49
+ wait_threads_active(waiting, num_threads)
50
+
51
+ # Let all threads proceed
52
+ barrier.unlock
53
+
54
+ # Wait for the threads to finish and collect our result
55
+ results = Set.new(promises.map { |p| p.resolve })
56
+
57
+ tp.shutdown
58
+
59
+ results.length.should == num_threads
60
+ end
61
+ end
62
+
63
+ describe "#enqueue" do
64
+ it "should raise an error if the pool is stopped" do
65
+ tp = VCAP::Concurrency::ThreadPool.new(1)
66
+
67
+ tp.stop
68
+ expect do
69
+ tp.enqueue { true }
70
+ end.to raise_error(/invalid state/i)
71
+ end
72
+
73
+ it "should be responsible for executing the supplied bock in a worker" do
74
+ tp = VCAP::Concurrency::ThreadPool.new(1)
75
+ expected_result = fib(5)
76
+ promise = tp.enqueue { fib(5) }
77
+
78
+ tp.start
79
+
80
+ result = promise.resolve
81
+
82
+ tp.shutdown
83
+
84
+ result.should == expected_result
85
+ end
86
+
87
+ it "should propagate exceptions thrown in the block" do
88
+ tp = VCAP::Concurrency::ThreadPool.new(1)
89
+ e = RuntimeError.new("test")
90
+ promise = tp.enqueue { raise e }
91
+
92
+ tp.start
93
+
94
+ expect do
95
+ promise.resolve
96
+ end.to raise_error(e)
97
+
98
+ tp.shutdown
99
+ end
100
+ end
101
+
102
+ describe "#stop" do
103
+ it "should allow existing work to be processed" do
104
+ waiting = VCAP::Concurrency::AtomicVar.new(0)
105
+ barrier = Mutex.new
106
+ num_threads = 5
107
+ promises = []
108
+ tp = VCAP::Concurrency::ThreadPool.new(num_threads)
109
+
110
+ # Each worker notifies the main thread that it is ready. When all workers
111
+ # have checked in, the main thread unblocks them all.
112
+ num_threads.times do |ii|
113
+ promises << tp.enqueue do
114
+ waiting.mutate { |v| v + 1 }
115
+
116
+ barrier.synchronize {}
117
+
118
+ ii
119
+ end
120
+ end
121
+
122
+ barrier.lock
123
+
124
+ tp.start
125
+
126
+ # Wait until all threads have checked in
127
+ wait_threads_active(waiting, num_threads)
128
+
129
+ # All threads are active here, but cannot proceed until we unlock the
130
+ # barrier. Thus, any work added here must live in the queue.
131
+ num_threads.times do |ii|
132
+ promises << tp.enqueue { ii + num_threads }
133
+ end
134
+
135
+ tp.stop
136
+
137
+ # Let all threads proceed
138
+ barrier.unlock
139
+
140
+ # Wait for the threads to finish and collect our results
141
+ results = promises.map { |p| p.resolve }
142
+
143
+ tp.join
144
+
145
+ results.length.should == 2 * num_threads
146
+ end
147
+ end
148
+
149
+ describe "#join" do
150
+ it "should raise an error unless the pool has been started or stopped" do
151
+ tp = VCAP::Concurrency::ThreadPool.new(5)
152
+ expect do
153
+ tp.join
154
+ end.to raise_error(/invalid state/i)
155
+ end
156
+ end
157
+
158
+ def wait_threads_active(counter, expected)
159
+ cur = 0
160
+ done = false
161
+ while (cur = counter.wait_value_changed(cur)) != expected
162
+ end
163
+ end
164
+
165
+ def fib(ii)
166
+ case ii
167
+ when 1
168
+ 1
169
+ when 0
170
+ 1
171
+ else
172
+ fib(ii - 1) + fib(ii - 2)
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/vcap/concurrency/version", __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["VMware"]
6
+ gem.email = ["support@vmware.com"]
7
+ gem.description = "Provides utility classes to support common patterns" \
8
+ + " in concurrent programming."
9
+ gem.summary = %q{Concurrency related utility classes}
10
+ gem.homepage = "http://www.cloudfoundry.org"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "vcap-concurrency"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = VCAP::Concurrency::VERSION
18
+
19
+ gem.add_development_dependency("ci_reporter")
20
+ gem.add_development_dependency("rake")
21
+ gem.add_development_dependency("rspec")
22
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vcap-concurrency
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - VMware
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ci_reporter
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Provides utility classes to support common patterns in concurrent programming.
63
+ email:
64
+ - support@vmware.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - LICENSE
72
+ - README.md
73
+ - Rakefile
74
+ - lib/vcap/concurrency.rb
75
+ - lib/vcap/concurrency/atomic_var.rb
76
+ - lib/vcap/concurrency/errors.rb
77
+ - lib/vcap/concurrency/promise.rb
78
+ - lib/vcap/concurrency/proxy.rb
79
+ - lib/vcap/concurrency/thread_pool.rb
80
+ - lib/vcap/concurrency/version.rb
81
+ - spec/atomic_var_spec.rb
82
+ - spec/promise_spec.rb
83
+ - spec/proxy_spec.rb
84
+ - spec/spec_helper.rb
85
+ - spec/thread_pool_spec.rb
86
+ - vcap-concurrency.gemspec
87
+ homepage: http://www.cloudfoundry.org
88
+ licenses: []
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 1.8.23
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: Concurrency related utility classes
111
+ test_files:
112
+ - spec/atomic_var_spec.rb
113
+ - spec/promise_spec.rb
114
+ - spec/proxy_spec.rb
115
+ - spec/spec_helper.rb
116
+ - spec/thread_pool_spec.rb