| Module | MonitorMixin |
| In: |
lib/monitor.rb
|
Adds monitor functionality to an arbitrary object by mixing the module with include. For example:
require 'monitor.rb'
buf = []
buf.extend(MonitorMixin)
empty_cond = buf.new_cond
# consumer
Thread.start do
loop do
buf.synchronize do
empty_cond.wait_while { buf.empty? }
print buf.shift
end
end
end
# producer
while line = ARGF.gets
buf.synchronize do
buf.push(line)
empty_cond.signal
end
end
The consumer thread waits for the producer thread to push a line to buf while buf.empty?, and the producer thread (main thread) reads a line from ARGF and push it to buf, then call empty_cond.signal.
# File lib/monitor.rb, line 185
185: def self.extend_object(obj)
186: super(obj)
187: obj.instance_eval {mon_initialize()}
188: end
Enters exclusive section.
# File lib/monitor.rb, line 212
212: def mon_enter
213: Thread.critical = true
214: mon_acquire(@mon_entering_queue)
215: @mon_count += 1
216: ensure
217: Thread.critical = false
218: end
Leaves exclusive section.
# File lib/monitor.rb, line 223
223: def mon_exit
224: mon_check_owner
225: Thread.critical = true
226: @mon_count -= 1
227: if @mon_count == 0
228: mon_release
229: end
230: Thread.critical = false
231: Thread.pass
232: end
Enters exclusive section and executes the block. Leaves the exclusive section automatically when the block exits. See example under MonitorMixin.
# File lib/monitor.rb, line 239
239: def mon_synchronize
240: mon_enter
241: begin
242: yield
243: ensure
244: mon_exit
245: end
246: end
Attempts to enter exclusive section. Returns false if lock fails.
# File lib/monitor.rb, line 193
193: def mon_try_enter
194: result = false
195: Thread.critical = true
196: if @mon_owner.nil?
197: @mon_owner = Thread.current
198: end
199: if @mon_owner == Thread.current
200: @mon_count += 1
201: result = true
202: end
203: Thread.critical = false
204: return result
205: end
# File lib/monitor.rb, line 282
282: def mon_acquire(queue)
283: while @mon_owner && @mon_owner != Thread.current
284: queue.push(Thread.current)
285: Thread.stop
286: Thread.critical = true
287: end
288: @mon_owner = Thread.current
289: end
Throw a ThreadError exception if the current thread does‘t own the monitor
# File lib/monitor.rb, line 276
276: def mon_check_owner
277: if @mon_owner != Thread.current
278: raise ThreadError, "current thread not owner"
279: end
280: end
# File lib/monitor.rb, line 302
302: def mon_enter_for_cond(count)
303: mon_acquire(@mon_waiting_queue)
304: @mon_count = count
305: end
# File lib/monitor.rb, line 307
307: def mon_exit_for_cond
308: count = @mon_count
309: @mon_count = 0
310: return count
311: ensure
312: mon_release
313: end
called by initialize method to set defaults for instance variables.
# File lib/monitor.rb, line 267
267: def mon_initialize
268: @mon_owner = nil
269: @mon_count = 0
270: @mon_entering_queue = []
271: @mon_waiting_queue = []
272: end
mon_release requires Thread.critical == true
# File lib/monitor.rb, line 292
292: def mon_release
293: @mon_owner = nil
294: while t = @mon_waiting_queue.shift || @mon_entering_queue.shift
295: if t.alive?
296: t.wakeup
297: return
298: end
299: end
300: end