concurrent-ruby 0.1.0 → 0.1.1.pre.1

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 (51) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +279 -224
  3. data/lib/concurrent.rb +27 -20
  4. data/lib/concurrent/agent.rb +106 -130
  5. data/lib/concurrent/cached_thread_pool.rb +130 -122
  6. data/lib/concurrent/defer.rb +67 -69
  7. data/lib/concurrent/drb_async_demux.rb +72 -0
  8. data/lib/concurrent/event.rb +60 -60
  9. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  10. data/lib/concurrent/executor.rb +87 -0
  11. data/lib/concurrent/fixed_thread_pool.rb +89 -89
  12. data/lib/concurrent/functions.rb +120 -0
  13. data/lib/concurrent/future.rb +52 -42
  14. data/lib/concurrent/global_thread_pool.rb +3 -3
  15. data/lib/concurrent/goroutine.rb +29 -25
  16. data/lib/concurrent/obligation.rb +67 -121
  17. data/lib/concurrent/promise.rb +172 -194
  18. data/lib/concurrent/reactor.rb +162 -0
  19. data/lib/concurrent/smart_mutex.rb +66 -0
  20. data/lib/concurrent/tcp_sync_demux.rb +96 -0
  21. data/lib/concurrent/thread_pool.rb +65 -61
  22. data/lib/concurrent/utilities.rb +34 -0
  23. data/lib/concurrent/version.rb +3 -3
  24. data/lib/concurrent_ruby.rb +1 -1
  25. data/md/agent.md +123 -123
  26. data/md/defer.md +174 -174
  27. data/md/event.md +32 -32
  28. data/md/executor.md +176 -0
  29. data/md/future.md +83 -83
  30. data/md/goroutine.md +52 -52
  31. data/md/obligation.md +32 -32
  32. data/md/promise.md +225 -225
  33. data/md/thread_pool.md +197 -197
  34. data/spec/concurrent/agent_spec.rb +376 -405
  35. data/spec/concurrent/cached_thread_pool_spec.rb +112 -112
  36. data/spec/concurrent/defer_spec.rb +209 -199
  37. data/spec/concurrent/event_machine_defer_proxy_spec.rb +250 -246
  38. data/spec/concurrent/event_spec.rb +134 -134
  39. data/spec/concurrent/executor_spec.rb +146 -0
  40. data/spec/concurrent/fixed_thread_pool_spec.rb +84 -84
  41. data/spec/concurrent/functions_spec.rb +57 -0
  42. data/spec/concurrent/future_spec.rb +125 -115
  43. data/spec/concurrent/goroutine_spec.rb +67 -52
  44. data/spec/concurrent/obligation_shared.rb +121 -121
  45. data/spec/concurrent/promise_spec.rb +299 -310
  46. data/spec/concurrent/smart_mutex_spec.rb +234 -0
  47. data/spec/concurrent/thread_pool_shared.rb +209 -209
  48. data/spec/concurrent/utilities_spec.rb +74 -0
  49. data/spec/spec_helper.rb +21 -19
  50. metadata +38 -14
  51. checksums.yaml +0 -7
@@ -0,0 +1,234 @@
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe SmartMutex do
6
+
7
+ subject{ SmartMutex.new }
8
+
9
+ def fly_solo
10
+ Thread.stub(:list).and_return(Array.new)
11
+ end
12
+
13
+ def run_with_the_pack
14
+ Thread.stub(:list).and_return([1,2,3,4])
15
+ end
16
+
17
+ context '#initialize' do
18
+
19
+ it 'creates a new mutex' do
20
+ Mutex.should_receive(:new).with(no_args())
21
+ SmartMutex.new
22
+ end
23
+ end
24
+
25
+ context '#alone?' do
26
+
27
+ it 'returns true when there is only one thread' do
28
+ fly_solo
29
+ subject.alone?.should be_true
30
+ end
31
+
32
+ it 'returns false when there is more than one thread' do
33
+ run_with_the_pack
34
+ subject.alone?.should be_false
35
+ end
36
+ end
37
+
38
+ context '#lock' do
39
+
40
+ it 'does not lock when there is only one thread' do
41
+ fly_solo
42
+
43
+ mutex = Mutex.new
44
+ mutex.should_not_receive(:lock)
45
+ Mutex.should_receive(:new).with(no_args()).and_return(mutex)
46
+
47
+ subject.lock
48
+ end
49
+
50
+ it 'locks when not locked and there is more than one thread' do
51
+ run_with_the_pack
52
+
53
+ mutex = Mutex.new
54
+ mutex.should_receive(:lock)
55
+ Mutex.should_receive(:new).with(no_args()).and_return(mutex)
56
+
57
+ subject.lock
58
+ end
59
+
60
+ it 'raises an exception when locked and there is more than one thread' do
61
+ run_with_the_pack
62
+ subject.lock
63
+ lambda {
64
+ subject.lock
65
+ }.should raise_error(ThreadError)
66
+ end
67
+
68
+ it 'does not raise an exception when lock called twice and there is only one thread' do
69
+ fly_solo
70
+ subject.lock
71
+ lambda {
72
+ subject.lock
73
+ }.should_not raise_error
74
+ end
75
+
76
+ it 'returns self' do
77
+ fly_solo
78
+ mutex = SmartMutex.new
79
+ mutex.lock.should eq mutex
80
+
81
+ run_with_the_pack
82
+ mutex.lock.should eq mutex
83
+ end
84
+ end
85
+
86
+ context '#locked?' do
87
+
88
+ it 'returns false when there is only one thread' do
89
+ fly_solo
90
+ subject.should_not be_locked
91
+ end
92
+
93
+ it 'returns true when locked and there is more than one thread' do
94
+ run_with_the_pack
95
+ subject.lock
96
+ subject.should be_locked
97
+ end
98
+
99
+ it 'returns false when not locked and there is more than one thread' do
100
+ run_with_the_pack
101
+ subject.should_not be_locked
102
+ end
103
+ end
104
+
105
+ context '#sleep' do
106
+
107
+ it 'sleeps when there is only one thread' do
108
+ fly_solo
109
+ Kernel.should_receive(:sleep).with(0.1).and_return(0.1)
110
+ subject.sleep(0.1)
111
+ end
112
+
113
+ it 'sleeps when locked and there is more than one thread' do
114
+ mutex = Mutex.new
115
+ mutex.should_receive(:sleep).with(0.1).and_return(0.1)
116
+ Mutex.should_receive(:new).with(no_args()).and_return(mutex)
117
+
118
+ run_with_the_pack
119
+ subject.lock
120
+ subject.sleep(0.1)
121
+ end
122
+
123
+ it 'raises an exception when not locked and there is more than one thread' do
124
+ run_with_the_pack
125
+ lambda {
126
+ subject.sleep(0.1)
127
+ }.should raise_error(ThreadError)
128
+ end
129
+
130
+ it 'returns the number of seconds slept' do
131
+ fly_solo
132
+ subject.sleep(1).should eq 1
133
+
134
+ run_with_the_pack
135
+ subject.lock
136
+ subject.sleep(1).should eq 1
137
+ end
138
+ end
139
+
140
+ context '#synchronize' do
141
+
142
+ it 'yields to the block when there is only one thread' do
143
+ fly_solo
144
+ @expected = false
145
+ subject.synchronize{ @expected = true }
146
+ @expected.should be_true
147
+ end
148
+
149
+ it 'locks when there is more than one thread' do
150
+ mutex = Mutex.new
151
+ mutex.should_receive(:synchronize).with(no_args())
152
+ Mutex.should_receive(:new).with(no_args()).and_return(mutex)
153
+
154
+ run_with_the_pack
155
+ subject.synchronize{ nil }
156
+ end
157
+
158
+ it 'yields to the block when there is more than one thread' do
159
+ run_with_the_pack
160
+ @expected = false
161
+ subject.synchronize{ @expected = true }
162
+ @expected.should be_true
163
+ end
164
+
165
+ it 'returns the result of the block' do
166
+ fly_solo
167
+ subject.synchronize{ 42 }.should eq 42
168
+
169
+ run_with_the_pack
170
+ subject.synchronize{ 42 }.should eq 42
171
+ end
172
+ end
173
+
174
+ context '#try_lock' do
175
+
176
+ it 'returns true when there is only one thread' do
177
+ fly_solo
178
+ subject.try_lock.should be_true
179
+ end
180
+
181
+ it 'returns true when the lock is obtained and there is more than one thread' do
182
+ run_with_the_pack
183
+ subject.try_lock.should be_true
184
+ end
185
+
186
+ it 'returns false when the lock is not obtained and there is more than one thread' do
187
+ run_with_the_pack
188
+ subject.lock
189
+ subject.try_lock.should be_false
190
+ end
191
+ end
192
+
193
+ context '#unlock' do
194
+
195
+ it 'does not unlock when there is only one thread' do
196
+ fly_solo
197
+
198
+ mutex = Mutex.new
199
+ mutex.should_not_receive(:unlock)
200
+ Mutex.should_receive(:new).with(no_args()).and_return(mutex)
201
+
202
+ subject.unlock
203
+ end
204
+
205
+ it 'unlocks when locked and there is more than one thread' do
206
+ run_with_the_pack
207
+
208
+ mutex = Mutex.new
209
+ mutex.should_receive(:unlock)
210
+ Mutex.should_receive(:new).with(no_args()).and_return(mutex)
211
+
212
+ subject.lock
213
+ subject.unlock
214
+ end
215
+
216
+ it 'raises an exception when not locked and there is more than one thread' do
217
+ run_with_the_pack
218
+ lambda {
219
+ subject.unlock
220
+ }.should raise_error(ThreadError)
221
+ end
222
+
223
+ it 'returns self' do
224
+ fly_solo
225
+ mutex = SmartMutex.new
226
+ mutex.unlock.should eq mutex
227
+
228
+ run_with_the_pack
229
+ mutex.lock
230
+ mutex.unlock.should eq mutex
231
+ end
232
+ end
233
+ end
234
+ end
@@ -1,209 +1,209 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- share_examples_for 'Thread Pool' do
6
-
7
- context '#running?' do
8
-
9
- it 'returns true when the thread pool is running' do
10
- subject.should be_running
11
- end
12
-
13
- it 'returns false when the thread pool is shutting down' do
14
- subject.post{ sleep(1) }
15
- subject.shutdown
16
- subject.should_not be_running
17
- end
18
-
19
- it 'returns false when the thread pool is shutdown' do
20
- subject.shutdown
21
- subject.should_not be_running
22
- end
23
-
24
- it 'returns false when the thread pool is killed' do
25
- subject.shutdown
26
- subject.should_not be_running
27
- end
28
- end
29
-
30
- context '#shutdown?' do
31
-
32
- it 'returns true if #shutdown has been called' do
33
- subject.shutdown
34
- subject.should be_shutdown
35
- end
36
-
37
- it 'returns false when running' do
38
- subject.should_not be_shutdown
39
- end
40
- end
41
-
42
- context '#killed?' do
43
-
44
- it 'returns true if tasks were killed at shutdown' do
45
- subject.post{ sleep(1) }
46
- subject.kill
47
- subject.should be_killed
48
- end
49
-
50
- it 'returns false when running' do
51
- subject.should_not be_killed
52
- end
53
- end
54
-
55
- context '#shutdown' do
56
-
57
- it 'stops accepting new tasks' do
58
- subject.post{ sleep(1) }
59
- subject.shutdown
60
- @expected = false
61
- subject.post{ @expected = true }.should be_false
62
- sleep(1)
63
- @expected.should be_false
64
- end
65
-
66
- it 'allows in-progress tasks to complete' do
67
- @expected = false
68
- subject.post{ sleep(0.5); @expected = true }
69
- subject.shutdown
70
- sleep(1)
71
- @expected.should be_true
72
- end
73
-
74
- it 'allows pending tasks to complete' do
75
- @expected = false
76
- subject.post{ sleep(0.2) }
77
- subject.post{ sleep(0.2); @expected = true }
78
- subject.shutdown
79
- sleep(1)
80
- @expected.should be_true
81
- end
82
-
83
- it 'allows threads to exit normally' do
84
- pool = FixedThreadPool.new(5)
85
- pool.shutdown
86
- sleep(1)
87
- pool.status.should be_empty
88
- end
89
- end
90
-
91
- context '#kill' do
92
-
93
- it 'stops accepting new tasks' do
94
- subject.post{ sleep(1) }
95
- subject.kill
96
- @expected = false
97
- subject.post{ @expected = true }.should be_false
98
- sleep(1)
99
- @expected.should be_false
100
- end
101
-
102
- it 'attempts to kill all in-progress tasks' do
103
- @expected = false
104
- subject.post{ sleep(1); @expected = true }
105
- subject.kill
106
- sleep(1)
107
- @expected.should be_false
108
- end
109
-
110
- it 'rejects all pending tasks' do
111
- @expected = false
112
- subject.post{ sleep(0.5) }
113
- subject.post{ sleep(0.5); @expected = true }
114
- subject.kill
115
- sleep(1)
116
- @expected.should be_false
117
- end
118
- end
119
-
120
- context '#wait_for_termination' do
121
-
122
- it 'immediately returns true after shutdown has complete' do
123
- subject.shutdown
124
- subject.wait_for_termination.should be_true
125
- end
126
-
127
- it 'blocks indefinitely when timeout it nil' do
128
- subject.post{ sleep(1) }
129
- subject.shutdown
130
- subject.wait_for_termination(nil).should be_true
131
- end
132
-
133
- it 'returns true when shutdown sucessfully completes before timeout' do
134
- subject.post{ sleep(0.5) }
135
- subject.shutdown
136
- subject.wait_for_termination(1).should be_true
137
- end
138
-
139
- it 'returns false when shutdown fails to complete before timeout' do
140
- subject.post{ sleep(1) }
141
- subject.shutdown
142
- subject.wait_for_termination(0.5).should be_true
143
- end
144
- end
145
-
146
- context '#post' do
147
-
148
- it 'raises an exception if no block is given' do
149
- lambda {
150
- subject.post
151
- }.should raise_error(ArgumentError)
152
- end
153
-
154
- it 'returns true when the block is added to the queue' do
155
- subject.post{ nil }.should be_true
156
- end
157
-
158
- it 'calls the block with the given arguments' do
159
- @expected = nil
160
- subject.post(1, 2, 3)do |a, b, c|
161
- @expected = a + b + c
162
- end
163
- sleep(0.1)
164
- @expected.should eq 6
165
- end
166
-
167
- it 'rejects the block while shutting down' do
168
- pool = FixedThreadPool.new(5)
169
- pool.post{ sleep(1) }
170
- pool.shutdown
171
- @expected = nil
172
- pool.post(1, 2, 3)do |a, b, c|
173
- @expected = a + b + c
174
- end
175
- @expected.should be_nil
176
- end
177
-
178
- it 'returns false while shutting down' do
179
- subject.post{ sleep(1) }
180
- subject.shutdown
181
- subject.post{ nil }.should be_false
182
- end
183
-
184
- it 'rejects the block once shutdown' do
185
- pool = FixedThreadPool.new(5)
186
- pool.shutdown
187
- @expected = nil
188
- pool.post(1, 2, 3)do |a, b, c|
189
- @expected = a + b + c
190
- end
191
- @expected.should be_nil
192
- end
193
-
194
- it 'returns false once shutdown' do
195
- subject.post{ nil }
196
- subject.shutdown
197
- sleep(0.1)
198
- subject.post{ nil }.should be_false
199
- end
200
-
201
- it 'aliases #<<' do
202
- @expected = false
203
- subject << proc { @expected = true }
204
- sleep(0.1)
205
- @expected.should be_true
206
- end
207
- end
208
- end
209
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ share_examples_for 'Thread Pool' do
6
+
7
+ context '#running?' do
8
+
9
+ it 'returns true when the thread pool is running' do
10
+ subject.should be_running
11
+ end
12
+
13
+ it 'returns false when the thread pool is shutting down' do
14
+ subject.post{ sleep(1) }
15
+ subject.shutdown
16
+ subject.should_not be_running
17
+ end
18
+
19
+ it 'returns false when the thread pool is shutdown' do
20
+ subject.shutdown
21
+ subject.should_not be_running
22
+ end
23
+
24
+ it 'returns false when the thread pool is killed' do
25
+ subject.shutdown
26
+ subject.should_not be_running
27
+ end
28
+ end
29
+
30
+ context '#shutdown?' do
31
+
32
+ it 'returns true if #shutdown has been called' do
33
+ subject.shutdown
34
+ subject.should be_shutdown
35
+ end
36
+
37
+ it 'returns false when running' do
38
+ subject.should_not be_shutdown
39
+ end
40
+ end
41
+
42
+ context '#killed?' do
43
+
44
+ it 'returns true if tasks were killed at shutdown' do
45
+ subject.post{ sleep(1) }
46
+ subject.kill
47
+ subject.should be_killed
48
+ end
49
+
50
+ it 'returns false when running' do
51
+ subject.should_not be_killed
52
+ end
53
+ end
54
+
55
+ context '#shutdown' do
56
+
57
+ it 'stops accepting new tasks' do
58
+ subject.post{ sleep(1) }
59
+ subject.shutdown
60
+ @expected = false
61
+ subject.post{ @expected = true }.should be_false
62
+ sleep(1)
63
+ @expected.should be_false
64
+ end
65
+
66
+ it 'allows in-progress tasks to complete' do
67
+ @expected = false
68
+ subject.post{ sleep(0.5); @expected = true }
69
+ subject.shutdown
70
+ sleep(1)
71
+ @expected.should be_true
72
+ end
73
+
74
+ it 'allows pending tasks to complete' do
75
+ @expected = false
76
+ subject.post{ sleep(0.2) }
77
+ subject.post{ sleep(0.2); @expected = true }
78
+ subject.shutdown
79
+ sleep(1)
80
+ @expected.should be_true
81
+ end
82
+
83
+ it 'allows threads to exit normally' do
84
+ pool = FixedThreadPool.new(5)
85
+ pool.shutdown
86
+ sleep(1)
87
+ pool.status.should be_empty
88
+ end
89
+ end
90
+
91
+ context '#kill' do
92
+
93
+ it 'stops accepting new tasks' do
94
+ subject.post{ sleep(1) }
95
+ subject.kill
96
+ @expected = false
97
+ subject.post{ @expected = true }.should be_false
98
+ sleep(1)
99
+ @expected.should be_false
100
+ end
101
+
102
+ it 'attempts to kill all in-progress tasks' do
103
+ @expected = false
104
+ subject.post{ sleep(1); @expected = true }
105
+ subject.kill
106
+ sleep(1)
107
+ @expected.should be_false
108
+ end
109
+
110
+ it 'rejects all pending tasks' do
111
+ @expected = false
112
+ subject.post{ sleep(0.5) }
113
+ subject.post{ sleep(0.5); @expected = true }
114
+ subject.kill
115
+ sleep(1)
116
+ @expected.should be_false
117
+ end
118
+ end
119
+
120
+ context '#wait_for_termination' do
121
+
122
+ it 'immediately returns true after shutdown has complete' do
123
+ subject.shutdown
124
+ subject.wait_for_termination.should be_true
125
+ end
126
+
127
+ it 'blocks indefinitely when timeout it nil' do
128
+ subject.post{ sleep(1) }
129
+ subject.shutdown
130
+ subject.wait_for_termination(nil).should be_true
131
+ end
132
+
133
+ it 'returns true when shutdown sucessfully completes before timeout' do
134
+ subject.post{ sleep(0.5) }
135
+ subject.shutdown
136
+ subject.wait_for_termination(1).should be_true
137
+ end
138
+
139
+ it 'returns false when shutdown fails to complete before timeout' do
140
+ subject.post{ sleep(1) }
141
+ subject.shutdown
142
+ subject.wait_for_termination(0.5).should be_true
143
+ end
144
+ end
145
+
146
+ context '#post' do
147
+
148
+ it 'raises an exception if no block is given' do
149
+ lambda {
150
+ subject.post
151
+ }.should raise_error(ArgumentError)
152
+ end
153
+
154
+ it 'returns true when the block is added to the queue' do
155
+ subject.post{ nil }.should be_true
156
+ end
157
+
158
+ it 'calls the block with the given arguments' do
159
+ @expected = nil
160
+ subject.post(1, 2, 3)do |a, b, c|
161
+ @expected = a + b + c
162
+ end
163
+ sleep(0.1)
164
+ @expected.should eq 6
165
+ end
166
+
167
+ it 'rejects the block while shutting down' do
168
+ pool = FixedThreadPool.new(5)
169
+ pool.post{ sleep(1) }
170
+ pool.shutdown
171
+ @expected = nil
172
+ pool.post(1, 2, 3)do |a, b, c|
173
+ @expected = a + b + c
174
+ end
175
+ @expected.should be_nil
176
+ end
177
+
178
+ it 'returns false while shutting down' do
179
+ subject.post{ sleep(1) }
180
+ subject.shutdown
181
+ subject.post{ nil }.should be_false
182
+ end
183
+
184
+ it 'rejects the block once shutdown' do
185
+ pool = FixedThreadPool.new(5)
186
+ pool.shutdown
187
+ @expected = nil
188
+ pool.post(1, 2, 3)do |a, b, c|
189
+ @expected = a + b + c
190
+ end
191
+ @expected.should be_nil
192
+ end
193
+
194
+ it 'returns false once shutdown' do
195
+ subject.post{ nil }
196
+ subject.shutdown
197
+ sleep(0.1)
198
+ subject.post{ nil }.should be_false
199
+ end
200
+
201
+ it 'aliases #<<' do
202
+ @expected = false
203
+ subject << proc { @expected = true }
204
+ sleep(0.1)
205
+ @expected.should be_true
206
+ end
207
+ end
208
+ end
209
+ end