2 # sync.rb - 2 phase lock with counter
3 # $Release Version: 1.0$
5 # by Keiju ISHITSUKA(keiju@ishitsuka.com)
8 # Sync_m, Synchronizer_m
18 # Sync_m#sync_locked?, locked?
19 # Sync_m#sync_shared?, shared?
20 # Sync_m#sync_exclusive?, sync_exclusive?
21 # Sync_m#sync_try_lock, try_lock
22 # Sync_m#sync_lock, lock
23 # Sync_m#sync_unlock, unlock
33 # Sync#try_lock(mode) -- mode = :EX, :SH, :UN
34 # Sync#lock(mode) -- mode = :EX, :SH, :UN
36 # Sync#synchronize(mode) {...}
40 unless defined? Thread
41 raise "Thread not available for this ruby interpreter"
53 class Err < StandardError
55 fail self, sprintf(self::Message, *opt)
58 class UnknownLocker < Err
59 Message = "Thread(%s) not locked."
60 def UnknownLocker.Fail(th)
65 class LockModeFailer < Err
66 Message = "Unknown lock mode(%s)"
67 def LockModeFailer.Fail(mode)
76 def Sync_m.define_aliases(cl)
78 alias locked? sync_locked?
79 alias shared? sync_shared?
80 alias exclusive? sync_exclusive?
82 alias unlock sync_unlock
83 alias try_lock sync_try_lock
84 alias synchronize sync_synchronize
88 def Sync_m.append_features(cl)
90 # do nothing for Modules
91 # make aliases for Classes.
92 define_aliases(cl) unless cl.instance_of?(Module)
96 def Sync_m.extend_object(obj)
102 unless (defined? locked? and
104 defined? exclusive? and
107 defined? try_lock and
108 defined? synchronize)
109 Sync_m.define_aliases(class<<self;self;end)
128 def sync_try_lock(mode = EX)
129 return unlock if sync_mode == UN
130 @sync_mutex.synchronize do
131 ret = sync_try_lock_sub(sync_mode)
136 def sync_lock(m = EX)
137 return unlock if m == UN
140 @sync_mutex.synchronize do
141 if 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)
148 sync_waiting.push Thread.current
157 def sync_unlock(m = EX)
159 @sync_mutex.synchronize do
161 Err::UnknownLocker.Fail(Thread.current)
164 m = sync_mode if m == EX and sync_mode == SH
169 Err::UnknownLocker.Fail(Thread.current)
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)
183 Err::UnknownLocker.Fail(Thread.current)
187 if (count = sync_sh_locker[Thread.current]).nil?
188 Err::UnknownLocker.Fail(Thread.current)
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
201 if sync_upgrade_waiting.size > 0
202 th, count = sync_upgrade_waiting.shift
203 sync_sh_locker[th] = count
205 wakeup_threads.push th
208 self.sync_waiting = []
211 wakeup_threads.push th
216 for th in wakeup_threads
222 def sync_synchronize(mode = EX)
231 attr_accessor :sync_mode
233 attr_accessor :sync_waiting
234 attr_accessor :sync_upgrade_waiting
235 attr_accessor :sync_sh_locker
236 attr_accessor :sync_ex_locker
237 attr_accessor :sync_ex_count
240 sync_iv = instance_variables.select{|iv| /^@sync_/ =~ iv.id2name}.collect{|iv| iv.id2name + '=' + instance_eval(iv.id2name).inspect}.join(",")
241 print "<#{self.class}.extend Sync_m: #{inspect}, <Sync_m: #{sync_iv}>"
249 @sync_upgrade_waiting = []
250 @sync_sh_locker = Hash.new
251 @sync_ex_locker = nil
254 @sync_mutex = Mutex.new
257 def initialize(*args)
262 def sync_try_lock_sub(m)
268 sync_sh_locker[Thread.current] = 1
271 count = 0 unless count = sync_sh_locker[Thread.current]
272 sync_sh_locker[Thread.current] = count + 1
275 # in EX mode, lock will upgrade to EX lock
276 if sync_ex_locker == Thread.current
277 self.sync_ex_count = sync_ex_count + 1
284 if sync_mode == UN or
285 sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
287 self.sync_ex_locker = Thread.current
288 self.sync_ex_count = 1
290 elsif sync_mode == EX && sync_ex_locker == Thread.current
291 self.sync_ex_count = sync_ex_count + 1
297 Err::LockModeFailer.Fail mode
302 Synchronizer_m = Sync_m