quack_concurrency 0.4.1 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/quack_concurrency/condition_variable.rb +116 -0
- data/lib/quack_concurrency/future.rb +43 -32
- data/lib/quack_concurrency/mutex.rb +121 -0
- data/lib/quack_concurrency/queue.rb +39 -39
- data/lib/quack_concurrency/reentrant_mutex.rb +92 -67
- data/lib/quack_concurrency/semaphore.rb +7 -7
- data/lib/quack_concurrency/uninterruptible_condition_variable.rb +79 -0
- data/lib/quack_concurrency/uninterruptible_sleeper.rb +73 -0
- data/lib/quack_concurrency/waiter.rb +42 -12
- data/lib/quack_concurrency/yielder.rb +35 -0
- data/lib/quack_concurrency.rb +8 -7
- data/spec/future_spec.rb +1 -34
- data/spec/queue_spec.rb +1 -34
- data/spec/reentrant_mutex_spec.rb +2 -33
- data/spec/semaphore_spec.rb +239 -272
- metadata +7 -4
- data/lib/quack_concurrency/concurrency_tool.rb +0 -28
- data/lib/quack_concurrency/name.rb +0 -33
data/spec/semaphore_spec.rb
CHANGED
@@ -1,277 +1,244 @@
|
|
1
|
-
require 'quack_concurrency'
|
1
|
+
#require 'quack_concurrency'
|
2
2
|
|
3
|
-
RSpec.describe QuackConcurrency::Semaphore do
|
3
|
+
#RSpec.describe QuackConcurrency::Semaphore do
|
4
4
|
|
5
|
-
describe "
|
5
|
+
#describe "#release" do
|
6
6
|
|
7
|
-
context "when called
|
8
|
-
it "should
|
9
|
-
semaphore = QuackConcurrency::Semaphore.new
|
10
|
-
expect(semaphore).to be_a(QuackConcurrency::Semaphore)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
context "when called with 'condition_variable' and 'mutex' duck types" do
|
15
|
-
it "should create a new QuackConcurrency::Semaphore" do
|
16
|
-
duck_types = {condition_variable: Class.new, mutex: Class.new}
|
17
|
-
semaphore = QuackConcurrency::Semaphore.new(duck_types: duck_types)
|
18
|
-
expect(semaphore).to be_a(QuackConcurrency::Semaphore)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
context "when called with only 'condition_variable' duck type" do
|
23
|
-
it "should raise ArgumentError" do
|
24
|
-
duck_types = {condition_variable: Class.new}
|
25
|
-
expect{ QuackConcurrency::Semaphore.new(duck_types: duck_types) }.to raise_error(ArgumentError)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context "when called with only 'mutex' duck type" do
|
30
|
-
it "should raise ArgumentError" do
|
31
|
-
duck_types = {mutex: Class.new}
|
32
|
-
expect{ QuackConcurrency::Semaphore.new(duck_types: duck_types) }.to raise_error(ArgumentError)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "#release" do
|
39
|
-
|
40
|
-
context "when called for the first time with many permits available" do
|
41
|
-
it "should not raise error" do
|
42
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
7
|
+
#context "when called for the first time with many permits available" do
|
8
|
+
#it "should not raise error" do
|
9
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
43
10
|
|
44
|
-
expect{ semaphore.release }.not_to raise_error
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context "when called a second time with one permit available" do
|
49
|
-
it "should not raise error" do
|
50
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
51
|
-
semaphore.release
|
52
|
-
expect{ semaphore.release }.not_to raise_error
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
describe "#release, #reacquire" do
|
59
|
-
|
60
|
-
context "when #release called with no permits available" do
|
61
|
-
it "should wait until #reacquire is called" do
|
62
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
63
|
-
semaphore.release
|
64
|
-
semaphore.release
|
65
|
-
thread = Thread.new do
|
66
|
-
sleep 1
|
67
|
-
semaphore.reacquire
|
68
|
-
end
|
69
|
-
start_time = Time.now
|
70
|
-
semaphore.release
|
71
|
-
end_time = Time.now
|
72
|
-
duration = end_time - start_time
|
73
|
-
thread.join
|
74
|
-
expect(duration).to be > 0.5
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context "when #reacquire called when all permits are available" do
|
79
|
-
it "should raise QuackConcurrency::Semaphore::Error" do
|
80
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
81
|
-
expect{ semaphore.reacquire }.to raise_error(QuackConcurrency::Semaphore::Error)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "#release, #reacquire, #permit_available?, #permits_available" do
|
88
|
-
|
89
|
-
context "#permit_available? and #permits_available" do
|
90
|
-
it "should work as expected" do
|
91
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
92
|
-
expect(semaphore.permit_available?).to eql true
|
93
|
-
expect(semaphore.permits_available).to eql 2
|
94
|
-
semaphore.release
|
95
|
-
expect(semaphore.permit_available?).to eql true
|
96
|
-
expect(semaphore.permits_available).to eql 1
|
97
|
-
semaphore.release
|
98
|
-
expect(semaphore.permit_available?).to eql false
|
99
|
-
expect(semaphore.permits_available).to eql 0
|
100
|
-
semaphore.reacquire
|
101
|
-
expect(semaphore.permit_available?).to eql true
|
102
|
-
expect(semaphore.permits_available).to eql 1
|
103
|
-
semaphore.reacquire
|
104
|
-
expect(semaphore.permit_available?).to eql true
|
105
|
-
expect(semaphore.permits_available).to eql 2
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "#set_permit_count, #permits_available" do
|
112
|
-
|
113
|
-
context "when #set_permit_count is called with more permits then currently exist" do
|
114
|
-
it "should add permits" do
|
115
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
116
|
-
expect(semaphore.permits_available).to eql 2
|
117
|
-
semaphore.set_permit_count(3)
|
118
|
-
expect(semaphore.permits_available).to eql 3
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
context "when #set_permit_count is called with less permits then currently exist" do
|
123
|
-
it "should remove permits" do
|
124
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
125
|
-
expect(semaphore.permits_available).to eql 2
|
126
|
-
semaphore.set_permit_count(1)
|
127
|
-
expect(semaphore.permits_available).to eql 1
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
end
|
132
|
-
|
133
|
-
describe "#set_permit_count, #permits_available, #release" do
|
134
|
-
|
135
|
-
context "when #set_permit_count is called with less permits then currently available" do
|
136
|
-
it "should raise QuackConcurrency::Semaphore::Error" do
|
137
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
138
|
-
expect(semaphore.permits_available).to eql 2
|
139
|
-
semaphore.release
|
140
|
-
semaphore.release
|
141
|
-
expect{ semaphore.set_permit_count(1) }.to raise_error(QuackConcurrency::Semaphore::Error)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
describe "#set_permit_count, #release" do
|
148
|
-
|
149
|
-
context "when #set_permit_count is called with more permits when one thread is waiting on #release" do
|
150
|
-
it "should resume the thread" do
|
151
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
152
|
-
semaphore.release
|
153
|
-
semaphore.release
|
154
|
-
thread = Thread.new do
|
155
|
-
sleep 1
|
156
|
-
semaphore.set_permit_count(3)
|
157
|
-
end
|
158
|
-
start_time = Time.now
|
159
|
-
semaphore.release
|
160
|
-
end_time = Time.now
|
161
|
-
duration = end_time - start_time
|
162
|
-
thread.join
|
163
|
-
expect(duration).to be > 0.5
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
end
|
168
|
-
|
169
|
-
describe "#set_permit_count!, #permits_available" do
|
170
|
-
|
171
|
-
context "when #set_permit_count! is called with more permits then currently exist" do
|
172
|
-
it "should add permits" do
|
173
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
174
|
-
expect(semaphore.permits_available).to eql 2
|
175
|
-
semaphore.set_permit_count!(3)
|
176
|
-
expect(semaphore.permits_available).to eql 3
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
context "when #set_permit_count! is called with less permits then currently exist" do
|
181
|
-
it "should remove permits" do
|
182
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
183
|
-
expect(semaphore.permits_available).to eql 2
|
184
|
-
semaphore.set_permit_count!(1)
|
185
|
-
expect(semaphore.permits_available).to eql 1
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
end
|
190
|
-
|
191
|
-
describe "#set_permit_count!, #permits_available, #release, #reacquire" do
|
192
|
-
|
193
|
-
context "when #set_permit_count! is called with less permits then currently available" do
|
194
|
-
it "should force new permit count" do
|
195
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
196
|
-
expect(semaphore.permits_available).to eql 2
|
197
|
-
semaphore.release
|
198
|
-
semaphore.release
|
199
|
-
semaphore.set_permit_count!(1)
|
200
|
-
expect(semaphore.permit_available?).to eql false
|
201
|
-
semaphore.reacquire
|
202
|
-
expect(semaphore.permit_available?).to eql false
|
203
|
-
semaphore.reacquire
|
204
|
-
expect(semaphore.permit_available?).to eql true
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
end
|
209
|
-
|
210
|
-
describe "#set_permit_count!, #release" do
|
211
|
-
|
212
|
-
context "when #set_permit_count! is called with more permits when one thread is waiting on #release" do
|
213
|
-
it "should resume the thread" do
|
214
|
-
semaphore = QuackConcurrency::Semaphore.new(2)
|
215
|
-
semaphore.release
|
216
|
-
semaphore.release
|
217
|
-
thread = Thread.new do
|
218
|
-
sleep 1
|
219
|
-
semaphore.set_permit_count(3)
|
220
|
-
end
|
221
|
-
start_time = Time.now
|
222
|
-
semaphore.release
|
223
|
-
end_time = Time.now
|
224
|
-
duration = end_time - start_time
|
225
|
-
thread.join
|
226
|
-
expect(duration).to be > 0.5
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
end
|
231
|
-
|
232
|
-
describe "#set_permit_count!, #release, #permit_available?" do
|
233
|
-
|
234
|
-
context "when semaphore has no permits available, them #set_permit_count! is called to remove 2 permits, then called again to add 1 permit" do
|
235
|
-
it "should not have any permits available" do
|
236
|
-
semaphore = QuackConcurrency::Semaphore.new(3)
|
237
|
-
semaphore.release
|
238
|
-
semaphore.release
|
239
|
-
expect(semaphore.permit_available?).to eql true
|
240
|
-
semaphore.set_permit_count!(1)
|
241
|
-
expect(semaphore.permit_available?).to eql false
|
242
|
-
semaphore.set_permit_count!(2)
|
243
|
-
expect(semaphore.permit_available?).to eql false
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
end
|
248
|
-
|
249
|
-
describe "#set_permit_count!, #release, #reacquire" do
|
250
|
-
|
251
|
-
context "when semaphore has no permits available, them #set_permit_count! is called to remove 2 permits, then a thread starts waiting for #release, then #set_permit_count! is called again to add 1 permit" do
|
252
|
-
it "thread should wait for #reacquire to be called" do
|
253
|
-
semaphore = QuackConcurrency::Semaphore.new(3)
|
254
|
-
semaphore.release
|
255
|
-
semaphore.release
|
256
|
-
semaphore.release
|
257
|
-
semaphore.set_permit_count!(1)
|
258
|
-
thread = Thread.new do
|
259
|
-
sleep 1
|
260
|
-
semaphore.set_permit_count!(2)
|
261
|
-
sleep 1
|
262
|
-
semaphore.reacquire
|
263
|
-
sleep 1
|
264
|
-
semaphore.reacquire
|
265
|
-
end
|
266
|
-
start_time = Time.now
|
267
|
-
semaphore.release
|
268
|
-
end_time = Time.now
|
269
|
-
duration = end_time - start_time
|
270
|
-
thread.join
|
271
|
-
expect(duration).to be_between(2.5, 3.5)
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
end
|
11
|
+
#expect{ semaphore.release }.not_to raise_error
|
12
|
+
#end
|
13
|
+
#end
|
14
|
+
|
15
|
+
#context "when called a second time with one permit available" do
|
16
|
+
#it "should not raise error" do
|
17
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
18
|
+
#semaphore.release
|
19
|
+
#expect{ semaphore.release }.not_to raise_error
|
20
|
+
#end
|
21
|
+
#end
|
22
|
+
|
23
|
+
#end
|
24
|
+
|
25
|
+
#describe "#release, #reacquire" do
|
26
|
+
|
27
|
+
#context "when #release called with no permits available" do
|
28
|
+
#it "should wait until #reacquire is called" do
|
29
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
30
|
+
#semaphore.release
|
31
|
+
#semaphore.release
|
32
|
+
#thread = Thread.new do
|
33
|
+
#sleep 1
|
34
|
+
#semaphore.reacquire
|
35
|
+
#end
|
36
|
+
#start_time = Time.now
|
37
|
+
#semaphore.release
|
38
|
+
#end_time = Time.now
|
39
|
+
#duration = end_time - start_time
|
40
|
+
#thread.join
|
41
|
+
#expect(duration).to be > 0.5
|
42
|
+
#end
|
43
|
+
#end
|
44
|
+
|
45
|
+
#context "when #reacquire called when all permits are available" do
|
46
|
+
#it "should raise QuackConcurrency::Semaphore::Error" do
|
47
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
48
|
+
#expect{ semaphore.reacquire }.to raise_error(QuackConcurrency::Semaphore::Error)
|
49
|
+
#end
|
50
|
+
#end
|
51
|
+
|
52
|
+
#end
|
53
|
+
|
54
|
+
#describe "#release, #reacquire, #permit_available?, #permits_available" do
|
55
|
+
|
56
|
+
#context "#permit_available? and #permits_available" do
|
57
|
+
#it "should work as expected" do
|
58
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
59
|
+
#expect(semaphore.permit_available?).to eql true
|
60
|
+
#expect(semaphore.permits_available).to eql 2
|
61
|
+
#semaphore.release
|
62
|
+
#expect(semaphore.permit_available?).to eql true
|
63
|
+
#expect(semaphore.permits_available).to eql 1
|
64
|
+
#semaphore.release
|
65
|
+
#expect(semaphore.permit_available?).to eql false
|
66
|
+
#expect(semaphore.permits_available).to eql 0
|
67
|
+
#semaphore.reacquire
|
68
|
+
#expect(semaphore.permit_available?).to eql true
|
69
|
+
#expect(semaphore.permits_available).to eql 1
|
70
|
+
#semaphore.reacquire
|
71
|
+
#expect(semaphore.permit_available?).to eql true
|
72
|
+
#expect(semaphore.permits_available).to eql 2
|
73
|
+
#end
|
74
|
+
#end
|
75
|
+
|
76
|
+
#end
|
77
|
+
|
78
|
+
#describe "#set_permit_count, #permits_available" do
|
79
|
+
|
80
|
+
#context "when #set_permit_count is called with more permits then currently exist" do
|
81
|
+
#it "should add permits" do
|
82
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
83
|
+
#expect(semaphore.permits_available).to eql 2
|
84
|
+
#semaphore.set_permit_count(3)
|
85
|
+
#expect(semaphore.permits_available).to eql 3
|
86
|
+
#end
|
87
|
+
#end
|
88
|
+
|
89
|
+
#context "when #set_permit_count is called with less permits then currently exist" do
|
90
|
+
#it "should remove permits" do
|
91
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
92
|
+
#expect(semaphore.permits_available).to eql 2
|
93
|
+
#semaphore.set_permit_count(1)
|
94
|
+
#expect(semaphore.permits_available).to eql 1
|
95
|
+
#end
|
96
|
+
#end
|
97
|
+
|
98
|
+
#end
|
99
|
+
|
100
|
+
#describe "#set_permit_count, #permits_available, #release" do
|
101
|
+
|
102
|
+
#context "when #set_permit_count is called with less permits then currently available" do
|
103
|
+
#it "should raise QuackConcurrency::Semaphore::Error" do
|
104
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
105
|
+
#expect(semaphore.permits_available).to eql 2
|
106
|
+
#semaphore.release
|
107
|
+
#semaphore.release
|
108
|
+
#expect{ semaphore.set_permit_count(1) }.to raise_error(QuackConcurrency::Semaphore::Error)
|
109
|
+
#end
|
110
|
+
#end
|
111
|
+
|
112
|
+
#end
|
113
|
+
|
114
|
+
#describe "#set_permit_count, #release" do
|
115
|
+
|
116
|
+
#context "when #set_permit_count is called with more permits when one thread is waiting on #release" do
|
117
|
+
#it "should resume the thread" do
|
118
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
119
|
+
#semaphore.release
|
120
|
+
#semaphore.release
|
121
|
+
#thread = Thread.new do
|
122
|
+
#sleep 1
|
123
|
+
#semaphore.set_permit_count(3)
|
124
|
+
#end
|
125
|
+
#start_time = Time.now
|
126
|
+
#semaphore.release
|
127
|
+
#end_time = Time.now
|
128
|
+
#duration = end_time - start_time
|
129
|
+
#thread.join
|
130
|
+
#expect(duration).to be > 0.5
|
131
|
+
#end
|
132
|
+
#end
|
133
|
+
|
134
|
+
#end
|
135
|
+
|
136
|
+
#describe "#set_permit_count!, #permits_available" do
|
137
|
+
|
138
|
+
#context "when #set_permit_count! is called with more permits then currently exist" do
|
139
|
+
#it "should add permits" do
|
140
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
141
|
+
#expect(semaphore.permits_available).to eql 2
|
142
|
+
#semaphore.set_permit_count!(3)
|
143
|
+
#expect(semaphore.permits_available).to eql 3
|
144
|
+
#end
|
145
|
+
#end
|
146
|
+
|
147
|
+
#context "when #set_permit_count! is called with less permits then currently exist" do
|
148
|
+
#it "should remove permits" do
|
149
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
150
|
+
#expect(semaphore.permits_available).to eql 2
|
151
|
+
#semaphore.set_permit_count!(1)
|
152
|
+
#expect(semaphore.permits_available).to eql 1
|
153
|
+
#end
|
154
|
+
#end
|
155
|
+
|
156
|
+
#end
|
157
|
+
|
158
|
+
#describe "#set_permit_count!, #permits_available, #release, #reacquire" do
|
159
|
+
|
160
|
+
#context "when #set_permit_count! is called with less permits then currently available" do
|
161
|
+
#it "should force new permit count" do
|
162
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
163
|
+
#expect(semaphore.permits_available).to eql 2
|
164
|
+
#semaphore.release
|
165
|
+
#semaphore.release
|
166
|
+
#semaphore.set_permit_count!(1)
|
167
|
+
#expect(semaphore.permit_available?).to eql false
|
168
|
+
#semaphore.reacquire
|
169
|
+
#expect(semaphore.permit_available?).to eql false
|
170
|
+
#semaphore.reacquire
|
171
|
+
#expect(semaphore.permit_available?).to eql true
|
172
|
+
#end
|
173
|
+
#end
|
174
|
+
|
175
|
+
#end
|
176
|
+
|
177
|
+
#describe "#set_permit_count!, #release" do
|
178
|
+
|
179
|
+
#context "when #set_permit_count! is called with more permits when one thread is waiting on #release" do
|
180
|
+
#it "should resume the thread" do
|
181
|
+
#semaphore = QuackConcurrency::Semaphore.new(2)
|
182
|
+
#semaphore.release
|
183
|
+
#semaphore.release
|
184
|
+
#thread = Thread.new do
|
185
|
+
#sleep 1
|
186
|
+
#semaphore.set_permit_count(3)
|
187
|
+
#end
|
188
|
+
#start_time = Time.now
|
189
|
+
#semaphore.release
|
190
|
+
#end_time = Time.now
|
191
|
+
#duration = end_time - start_time
|
192
|
+
#thread.join
|
193
|
+
#expect(duration).to be > 0.5
|
194
|
+
#end
|
195
|
+
#end
|
196
|
+
|
197
|
+
#end
|
198
|
+
|
199
|
+
#describe "#set_permit_count!, #release, #permit_available?" do
|
200
|
+
|
201
|
+
#context "when semaphore has no permits available, them #set_permit_count! is called to remove 2 permits, then called again to add 1 permit" do
|
202
|
+
#it "should not have any permits available" do
|
203
|
+
#semaphore = QuackConcurrency::Semaphore.new(3)
|
204
|
+
#semaphore.release
|
205
|
+
#semaphore.release
|
206
|
+
#expect(semaphore.permit_available?).to eql true
|
207
|
+
#semaphore.set_permit_count!(1)
|
208
|
+
#expect(semaphore.permit_available?).to eql false
|
209
|
+
#semaphore.set_permit_count!(2)
|
210
|
+
#expect(semaphore.permit_available?).to eql false
|
211
|
+
#end
|
212
|
+
#end
|
213
|
+
|
214
|
+
#end
|
215
|
+
|
216
|
+
#describe "#set_permit_count!, #release, #reacquire" do
|
217
|
+
|
218
|
+
#context "when semaphore has no permits available, them #set_permit_count! is called to remove 2 permits, then a thread starts waiting for #release, then #set_permit_count! is called again to add 1 permit" do
|
219
|
+
#it "thread should wait for #reacquire to be called" do
|
220
|
+
#semaphore = QuackConcurrency::Semaphore.new(3)
|
221
|
+
#semaphore.release
|
222
|
+
#semaphore.release
|
223
|
+
#semaphore.release
|
224
|
+
#semaphore.set_permit_count!(1)
|
225
|
+
#thread = Thread.new do
|
226
|
+
#sleep 1
|
227
|
+
#semaphore.set_permit_count!(2)
|
228
|
+
#sleep 1
|
229
|
+
#semaphore.reacquire
|
230
|
+
#sleep 1
|
231
|
+
#semaphore.reacquire
|
232
|
+
#end
|
233
|
+
#start_time = Time.now
|
234
|
+
#semaphore.release
|
235
|
+
#end_time = Time.now
|
236
|
+
#duration = end_time - start_time
|
237
|
+
#thread.join
|
238
|
+
#expect(duration).to be_between(2.5, 3.5)
|
239
|
+
#end
|
240
|
+
#end
|
241
|
+
|
242
|
+
#end
|
276
243
|
|
277
|
-
end
|
244
|
+
#end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quack_concurrency
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Fors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Offers concurrency tools that could also be found in the 'Concurrent
|
14
14
|
Ruby'. However, all these tools will also accept core class duck types to build
|
@@ -22,19 +22,22 @@ files:
|
|
22
22
|
- README.md
|
23
23
|
- Rakefile
|
24
24
|
- lib/quack_concurrency.rb
|
25
|
-
- lib/quack_concurrency/
|
25
|
+
- lib/quack_concurrency/condition_variable.rb
|
26
26
|
- lib/quack_concurrency/error.rb
|
27
27
|
- lib/quack_concurrency/future.rb
|
28
28
|
- lib/quack_concurrency/future/canceled.rb
|
29
29
|
- lib/quack_concurrency/future/complete.rb
|
30
|
-
- lib/quack_concurrency/
|
30
|
+
- lib/quack_concurrency/mutex.rb
|
31
31
|
- lib/quack_concurrency/queue.rb
|
32
32
|
- lib/quack_concurrency/queue/error.rb
|
33
33
|
- lib/quack_concurrency/reentrant_mutex.rb
|
34
34
|
- lib/quack_concurrency/reentrant_mutex/error.rb
|
35
35
|
- lib/quack_concurrency/semaphore.rb
|
36
36
|
- lib/quack_concurrency/semaphore/error.rb
|
37
|
+
- lib/quack_concurrency/uninterruptible_condition_variable.rb
|
38
|
+
- lib/quack_concurrency/uninterruptible_sleeper.rb
|
37
39
|
- lib/quack_concurrency/waiter.rb
|
40
|
+
- lib/quack_concurrency/yielder.rb
|
38
41
|
- spec/future_spec.rb
|
39
42
|
- spec/queue_spec.rb
|
40
43
|
- spec/reentrant_mutex_spec.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module QuackConcurrency
|
2
|
-
|
3
|
-
# @api private
|
4
|
-
class ConcurrencyTool
|
5
|
-
|
6
|
-
def setup_duck_types(supplied_classes)
|
7
|
-
resultant_classes = {}
|
8
|
-
required_classes = [:condition_variable, :mutex]
|
9
|
-
required_classes = required_classes.map { |name| Name.new(name.to_s) }
|
10
|
-
if supplied_classes
|
11
|
-
raise ArgumentError, "'supplied_classes' must be Hash" unless supplied_classes.is_a?(Hash)
|
12
|
-
supplied_classes = supplied_classes.map { |k, v| [Name.new(k.to_s), v] }.to_h
|
13
|
-
required_classes.each do |class_name|
|
14
|
-
unless supplied_classes[class_name]
|
15
|
-
raise ArgumentError, "missing duck type: #{class_name.camel_case(:upper)}"
|
16
|
-
end
|
17
|
-
resultant_classes[class_name.snake_case.to_sym] = supplied_classes[class_name]
|
18
|
-
end
|
19
|
-
else
|
20
|
-
required_classes.each do |class_name|
|
21
|
-
resultant_classes[class_name.snake_case.to_sym] = Object.const_get(class_name.camel_case(:upper))
|
22
|
-
end
|
23
|
-
end
|
24
|
-
resultant_classes
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module QuackConcurrency
|
2
|
-
|
3
|
-
# @api private
|
4
|
-
class Name < String
|
5
|
-
|
6
|
-
def initialize(*args)
|
7
|
-
super
|
8
|
-
# set all names to a default case
|
9
|
-
# if we create two of the same name with different cases they will now be equal
|
10
|
-
replace(snake_case)
|
11
|
-
end
|
12
|
-
|
13
|
-
def camel_case(first_letter = :upper)
|
14
|
-
case first_letter
|
15
|
-
when :upper
|
16
|
-
self.split('_').collect(&:capitalize).join
|
17
|
-
when :lower
|
18
|
-
self.camelcase(:upper)[0].downcase + self.camelcase(:upper)[1..-1]
|
19
|
-
else
|
20
|
-
raise ArgumentError, 'invalid option, use either :upper or :lower'
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def snake_case
|
25
|
-
self.gsub(/::/, '/').
|
26
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
27
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
28
|
-
tr("- ", "_").
|
29
|
-
downcase
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|