1 | #
|
---|
2 | # sync.rb - 2 phase lock with counter
|
---|
3 | # $Release Version: 1.0$
|
---|
4 | # $Revision: 11708 $
|
---|
5 | # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $
|
---|
6 | # by Keiju ISHITSUKA([email protected])
|
---|
7 | #
|
---|
8 | # --
|
---|
9 | # Sync_m, Synchronizer_m
|
---|
10 | # Usage:
|
---|
11 | # obj.extend(Sync_m)
|
---|
12 | # or
|
---|
13 | # class Foo
|
---|
14 | # include Sync_m
|
---|
15 | # :
|
---|
16 | # end
|
---|
17 | #
|
---|
18 | # Sync_m#sync_mode
|
---|
19 | # Sync_m#sync_locked?, locked?
|
---|
20 | # Sync_m#sync_shared?, shared?
|
---|
21 | # Sync_m#sync_exclusive?, sync_exclusive?
|
---|
22 | # Sync_m#sync_try_lock, try_lock
|
---|
23 | # Sync_m#sync_lock, lock
|
---|
24 | # Sync_m#sync_unlock, unlock
|
---|
25 | #
|
---|
26 | # Sync, Synchronicer:
|
---|
27 | # include Sync_m
|
---|
28 | # Usage:
|
---|
29 | # sync = Sync.new
|
---|
30 | #
|
---|
31 | # Sync#mode
|
---|
32 | # Sync#locked?
|
---|
33 | # Sync#shared?
|
---|
34 | # Sync#exclusive?
|
---|
35 | # Sync#try_lock(mode) -- mode = :EX, :SH, :UN
|
---|
36 | # Sync#lock(mode) -- mode = :EX, :SH, :UN
|
---|
37 | # Sync#unlock
|
---|
38 | # Sync#synchronize(mode) {...}
|
---|
39 | #
|
---|
40 | #
|
---|
41 |
|
---|
42 | unless defined? Thread
|
---|
43 | fail "Thread not available for this ruby interpreter"
|
---|
44 | end
|
---|
45 |
|
---|
46 | module Sync_m
|
---|
47 | RCS_ID='-$Header$-'
|
---|
48 |
|
---|
49 | # lock mode
|
---|
50 | UN = :UN
|
---|
51 | SH = :SH
|
---|
52 | EX = :EX
|
---|
53 |
|
---|
54 | # exceptions
|
---|
55 | class Err < StandardError
|
---|
56 | def Err.Fail(*opt)
|
---|
57 | fail self, sprintf(self::Message, *opt)
|
---|
58 | end
|
---|
59 |
|
---|
60 | class UnknownLocker < Err
|
---|
61 | Message = "Thread(%s) not locked."
|
---|
62 | def UnknownLocker.Fail(th)
|
---|
63 | super(th.inspect)
|
---|
64 | end
|
---|
65 | end
|
---|
66 |
|
---|
67 | class LockModeFailer < Err
|
---|
68 | Message = "Unknown lock mode(%s)"
|
---|
69 | def LockModeFailer.Fail(mode)
|
---|
70 | if mode.id2name
|
---|
71 | mode = id2name
|
---|
72 | end
|
---|
73 | super(mode)
|
---|
74 | end
|
---|
75 | end
|
---|
76 | end
|
---|
77 |
|
---|
78 | def Sync_m.define_aliases(cl)
|
---|
79 | cl.module_eval %q{
|
---|
80 | alias locked? sync_locked?
|
---|
81 | alias shared? sync_shared?
|
---|
82 | alias exclusive? sync_exclusive?
|
---|
83 | alias lock sync_lock
|
---|
84 | alias unlock sync_unlock
|
---|
85 | alias try_lock sync_try_lock
|
---|
86 | alias synchronize sync_synchronize
|
---|
87 | }
|
---|
88 | end
|
---|
89 |
|
---|
90 | def Sync_m.append_features(cl)
|
---|
91 | super
|
---|
92 | unless cl.instance_of?(Module)
|
---|
93 | # do nothing for Modules
|
---|
94 | # make aliases and include the proper module.
|
---|
95 | define_aliases(cl)
|
---|
96 | end
|
---|
97 | end
|
---|
98 |
|
---|
99 | def Sync_m.extend_object(obj)
|
---|
100 | super
|
---|
101 | obj.sync_extended
|
---|
102 | end
|
---|
103 |
|
---|
104 | def sync_extended
|
---|
105 | unless (defined? locked? and
|
---|
106 | defined? shared? and
|
---|
107 | defined? exclusive? and
|
---|
108 | defined? lock and
|
---|
109 | defined? unlock and
|
---|
110 | defined? try_lock and
|
---|
111 | defined? synchronize)
|
---|
112 | Sync_m.define_aliases(class<<self;self;end)
|
---|
113 | end
|
---|
114 | sync_initialize
|
---|
115 | end
|
---|
116 |
|
---|
117 | # accessing
|
---|
118 | def sync_locked?
|
---|
119 | sync_mode != UN
|
---|
120 | end
|
---|
121 |
|
---|
122 | def sync_shared?
|
---|
123 | sync_mode == SH
|
---|
124 | end
|
---|
125 |
|
---|
126 | def sync_exclusive?
|
---|
127 | sync_mode == EX
|
---|
128 | end
|
---|
129 |
|
---|
130 | # locking methods.
|
---|
131 | def sync_try_lock(mode = EX)
|
---|
132 | return unlock if sync_mode == UN
|
---|
133 |
|
---|
134 | Thread.critical = true
|
---|
135 | ret = sync_try_lock_sub(sync_mode)
|
---|
136 | Thread.critical = false
|
---|
137 | ret
|
---|
138 | end
|
---|
139 |
|
---|
140 | def sync_lock(m = EX)
|
---|
141 | return unlock if m == UN
|
---|
142 |
|
---|
143 | until (Thread.critical = true; sync_try_lock_sub(m))
|
---|
144 | if sync_sh_locker[Thread.current]
|
---|
145 | sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
|
---|
146 | sync_sh_locker.delete(Thread.current)
|
---|
147 | else
|
---|
148 | sync_waiting.push Thread.current
|
---|
149 | end
|
---|
150 | Thread.stop
|
---|
151 | end
|
---|
152 | Thread.critical = false
|
---|
153 | self
|
---|
154 | end
|
---|
155 |
|
---|
156 | def sync_unlock(m = EX)
|
---|
157 | Thread.critical = true
|
---|
158 | if sync_mode == UN
|
---|
159 | Thread.critical = false
|
---|
160 | Err::UnknownLocker.Fail(Thread.current)
|
---|
161 | end
|
---|
162 |
|
---|
163 | m = sync_mode if m == EX and sync_mode == SH
|
---|
164 |
|
---|
165 | runnable = false
|
---|
166 | case m
|
---|
167 | when UN
|
---|
168 | Thread.critical = false
|
---|
169 | Err::UnknownLocker.Fail(Thread.current)
|
---|
170 |
|
---|
171 | when EX
|
---|
172 | if sync_ex_locker == Thread.current
|
---|
173 | if (self.sync_ex_count = sync_ex_count - 1) == 0
|
---|
174 | self.sync_ex_locker = nil
|
---|
175 | if sync_sh_locker.include?(Thread.current)
|
---|
176 | self.sync_mode = SH
|
---|
177 | else
|
---|
178 | self.sync_mode = UN
|
---|
179 | end
|
---|
180 | runnable = true
|
---|
181 | end
|
---|
182 | else
|
---|
183 | Err::UnknownLocker.Fail(Thread.current)
|
---|
184 | end
|
---|
185 |
|
---|
186 | when SH
|
---|
187 | if (count = sync_sh_locker[Thread.current]).nil?
|
---|
188 | Err::UnknownLocker.Fail(Thread.current)
|
---|
189 | else
|
---|
190 | if (sync_sh_locker[Thread.current] = count - 1) == 0
|
---|
191 | sync_sh_locker.delete(Thread.current)
|
---|
192 | if sync_sh_locker.empty? and sync_ex_count == 0
|
---|
193 | self.sync_mode = UN
|
---|
194 | runnable = true
|
---|
195 | end
|
---|
196 | end
|
---|
197 | end
|
---|
198 | end
|
---|
199 |
|
---|
200 | if runnable
|
---|
201 | if sync_upgrade_waiting.size > 0
|
---|
202 | for k, v in sync_upgrade_waiting
|
---|
203 | sync_sh_locker[k] = v
|
---|
204 | end
|
---|
205 | wait = sync_upgrade_waiting
|
---|
206 | self.sync_upgrade_waiting = []
|
---|
207 | Thread.critical = false
|
---|
208 |
|
---|
209 | for w, v in wait
|
---|
210 | w.run
|
---|
211 | end
|
---|
212 | else
|
---|
213 | wait = sync_waiting
|
---|
214 | self.sync_waiting = []
|
---|
215 | Thread.critical = false
|
---|
216 | for w in wait
|
---|
217 | w.run
|
---|
218 | end
|
---|
219 | end
|
---|
220 | end
|
---|
221 |
|
---|
222 | Thread.critical = false
|
---|
223 | self
|
---|
224 | end
|
---|
225 |
|
---|
226 | def sync_synchronize(mode = EX)
|
---|
227 | begin
|
---|
228 | sync_lock(mode)
|
---|
229 | yield
|
---|
230 | ensure
|
---|
231 | sync_unlock
|
---|
232 | end
|
---|
233 | end
|
---|
234 |
|
---|
235 | attr :sync_mode, true
|
---|
236 |
|
---|
237 | attr :sync_waiting, true
|
---|
238 | attr :sync_upgrade_waiting, true
|
---|
239 | attr :sync_sh_locker, true
|
---|
240 | attr :sync_ex_locker, true
|
---|
241 | attr :sync_ex_count, true
|
---|
242 |
|
---|
243 | private
|
---|
244 |
|
---|
245 | def sync_initialize
|
---|
246 | @sync_mode = UN
|
---|
247 | @sync_waiting = []
|
---|
248 | @sync_upgrade_waiting = []
|
---|
249 | @sync_sh_locker = Hash.new
|
---|
250 | @sync_ex_locker = nil
|
---|
251 | @sync_ex_count = 0
|
---|
252 | end
|
---|
253 |
|
---|
254 | def initialize(*args)
|
---|
255 | sync_initialize
|
---|
256 | super
|
---|
257 | end
|
---|
258 |
|
---|
259 | def sync_try_lock_sub(m)
|
---|
260 | case m
|
---|
261 | when SH
|
---|
262 | case sync_mode
|
---|
263 | when UN
|
---|
264 | self.sync_mode = m
|
---|
265 | sync_sh_locker[Thread.current] = 1
|
---|
266 | ret = true
|
---|
267 | when SH
|
---|
268 | count = 0 unless count = sync_sh_locker[Thread.current]
|
---|
269 | sync_sh_locker[Thread.current] = count + 1
|
---|
270 | ret = true
|
---|
271 | when EX
|
---|
272 | # in EX mode, lock will upgrade to EX lock
|
---|
273 | if sync_ex_locker == Thread.current
|
---|
274 | self.sync_ex_count = sync_ex_count + 1
|
---|
275 | ret = true
|
---|
276 | else
|
---|
277 | ret = false
|
---|
278 | end
|
---|
279 | end
|
---|
280 | when EX
|
---|
281 | if sync_mode == UN or
|
---|
282 | sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
|
---|
283 | self.sync_mode = m
|
---|
284 | self.sync_ex_locker = Thread.current
|
---|
285 | self.sync_ex_count = 1
|
---|
286 | ret = true
|
---|
287 | elsif sync_mode == EX && sync_ex_locker == Thread.current
|
---|
288 | self.sync_ex_count = sync_ex_count + 1
|
---|
289 | ret = true
|
---|
290 | else
|
---|
291 | ret = false
|
---|
292 | end
|
---|
293 | else
|
---|
294 | Thread.critical = false
|
---|
295 | Err::LockModeFailer.Fail mode
|
---|
296 | end
|
---|
297 | return ret
|
---|
298 | end
|
---|
299 | end
|
---|
300 | Synchronizer_m = Sync_m
|
---|
301 |
|
---|
302 | class Sync
|
---|
303 | #Sync_m.extend_class self
|
---|
304 | include Sync_m
|
---|
305 |
|
---|
306 | def initialize
|
---|
307 | super
|
---|
308 | end
|
---|
309 |
|
---|
310 | end
|
---|
311 | Synchronizer = Sync
|
---|