vcap-concurrency 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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