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