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 185
185:   def self.extend_object(obj)
186:     super(obj)
187:     obj.instance_eval {mon_initialize()}
188:   end

[Source]

     # File lib/monitor.rb, line 261
261:   def initialize(*args)
262:     super
263:     mon_initialize
264:   end

Public Instance methods

Enters exclusive section.

[Source]

     # 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.

[Source]

     # 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.

[Source]

     # 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.

[Source]

     # 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

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 255
255:   def new_cond
256:     return ConditionVariable.new(self)
257:   end
synchronize()

Alias for mon_synchronize

try_mon_enter()

Alias for mon_try_enter

Private Instance methods

[Source]

     # 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

[Source]

     # 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

[Source]

     # 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

[Source]

     # 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.

[Source]

     # 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

[Source]

     # 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

[Validate]