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.

Methods

Classes and Modules

Class MonitorMixin::ConditionVariable

Public Class methods

[Source]

     # File lib/monitor.rb, line 182
182:   def self.extend_object(obj)
183:     super(obj)
184:     obj.instance_eval {mon_initialize()}
185:   end

[Source]

     # File lib/monitor.rb, line 257
257:   def initialize(*args)
258:     super
259:     mon_initialize
260:   end

Public Instance methods

Enters exclusive section.

[Source]

     # File lib/monitor.rb, line 209
209:   def mon_enter
210:     Thread.critical = true
211:     mon_acquire(@mon_entering_queue)
212:     @mon_count += 1
213:     Thread.critical = false
214:   end

Leaves exclusive section.

[Source]

     # File lib/monitor.rb, line 219
219:   def mon_exit
220:     mon_check_owner
221:     Thread.critical = true
222:     @mon_count -= 1
223:     if @mon_count == 0
224:       mon_release
225:     end
226:     Thread.critical = false
227:     Thread.pass
228:   end

Enters exclusive section and executes the block. Leaves the exclusive section automatically when the block exits. See example under MonitorMixin.

[Source]

     # File lib/monitor.rb, line 235
235:   def mon_synchronize
236:     mon_enter
237:     begin
238:       yield
239:     ensure
240:       mon_exit
241:     end
242:   end

Attempts to enter exclusive section. Returns false if lock fails.

[Source]

     # File lib/monitor.rb, line 190
190:   def mon_try_enter
191:     result = false
192:     Thread.critical = true
193:     if @mon_owner.nil?
194:       @mon_owner = Thread.current
195:     end
196:     if @mon_owner == Thread.current
197:       @mon_count += 1
198:       result = true
199:     end
200:     Thread.critical = false
201:     return result
202:   end

FIXME: This isn‘t documented in Nutshell.

Create a new condition variable for this monitor. This facilitates control of the monitor with signal and wait.

[Source]

     # File lib/monitor.rb, line 251
251:   def new_cond
252:     return ConditionVariable.new(self)
253:   end
synchronize()

Alias for mon_synchronize

try_mon_enter()

Alias for mon_try_enter

Private Instance methods

[Source]

     # File lib/monitor.rb, line 278
278:   def mon_acquire(queue)
279:     while @mon_owner && @mon_owner != Thread.current
280:       queue.push(Thread.current)
281:       Thread.stop
282:       Thread.critical = true
283:     end
284:     @mon_owner = Thread.current
285:   end

Throw a ThreadError exception if the current thread does‘t own the monitor

[Source]

     # File lib/monitor.rb, line 272
272:   def mon_check_owner
273:     if @mon_owner != Thread.current
274:       raise ThreadError, "current thread not owner"
275:     end
276:   end

[Source]

     # File lib/monitor.rb, line 294
294:   def mon_enter_for_cond(count)
295:     mon_acquire(@mon_waiting_queue)
296:     @mon_count = count
297:   end

[Source]

     # File lib/monitor.rb, line 299
299:   def mon_exit_for_cond
300:     count = @mon_count
301:     @mon_count = 0
302:     mon_release
303:     return count
304:   end

called by initialize method to set defaults for instance variables.

[Source]

     # File lib/monitor.rb, line 263
263:   def mon_initialize
264:     @mon_owner = nil
265:     @mon_count = 0
266:     @mon_entering_queue = []
267:     @mon_waiting_queue = []
268:   end

[Source]

     # File lib/monitor.rb, line 287
287:   def mon_release
288:     @mon_owner = nil
289:     t = @mon_waiting_queue.shift
290:     t = @mon_entering_queue.shift unless t
291:     t.wakeup if t
292:   end

[Validate]