-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathmutex_spec.cr
146 lines (122 loc) · 2.76 KB
/
mutex_spec.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
require "spec"
require "../support/fibers"
describe Mutex do
it "locks and unlocks" do
mutex = Mutex.new
mutex.lock
mutex.unlock
end
it "works with multiple threads" do
x = 0
mutex = Mutex.new
fibers = 10.times.map do
spawn do
100.times do
mutex.synchronize { x += 1 }
end
end
end.to_a
fibers.each do |f|
wait_until_finished f
end
x.should eq(1000)
end
describe "checked" do
it "raises if locked recursively" do
mutex = Mutex.new
mutex.lock
expect_raises(Exception, "Attempt to lock a mutex recursively (deadlock)") do
mutex.lock
end
end
it "raises if unlocks without lock" do
mutex = Mutex.new
expect_raises(Exception, "Attempt to unlock a mutex which is not locked") do
mutex.unlock
end
end
it "can't be unlocked by another fiber" do
mutex = nil
done = false
spawn do
mutex = Mutex.new
mutex.not_nil!.lock
done = true
end
until done
Fiber.yield
end
expect_raises(Exception, "Attempt to unlock a mutex locked by another fiber") do
mutex.not_nil!.unlock
end
end
end
describe "reentrant" do
it "can be locked many times from the same fiber" do
mutex = Mutex.new(:reentrant)
mutex.lock
mutex.lock
mutex.unlock
mutex.unlock
end
it "raises if unlocks without lock" do
mutex = Mutex.new(:reentrant)
expect_raises(Exception, "Attempt to unlock a mutex which is not locked") do
mutex.unlock
end
end
it "can't be unlocked by another fiber" do
mutex = nil
done = false
spawn do
mutex = Mutex.new(:reentrant)
mutex.not_nil!.lock
done = true
end
until done
Fiber.yield
end
expect_raises(Exception, "Attempt to unlock a mutex locked by another fiber") do
mutex.not_nil!.unlock
end
end
end
describe "unchecked" do
it "can lock and unlock from multiple fibers" do
mutex = Mutex.new(:unchecked)
a = 1
two = false
three = false
four = false
ch = Channel(Nil).new
spawn do
mutex.synchronize do
a = 2
Fiber.yield
two = a == 2
end
ch.send(nil)
end
spawn do
mutex.synchronize do
a = 3
Fiber.yield
three = a == 3
end
ch.send(nil)
end
spawn do
mutex.synchronize do
a = 4
Fiber.yield
four = a == 4
end
ch.send(nil)
end
3.times { ch.receive }
two.should be_true
three.should be_true
four.should be_true
end
end
end