Bug #4823 » 0001-enhanced-monitor-doc.patch
lib/monitor.rb | ||
---|---|---|
=begin
|
||
= monitor.rb
|
||
Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
|
||
This library is distributed under the terms of the Ruby license.
|
||
You can freely distribute/modify this library.
|
||
== example
|
||
This is a simple 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.
|
||
=end
|
||
# = monitor.rb
|
||
#
|
||
# Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
|
||
#
|
||
# This library is distributed under the terms of the Ruby license.
|
||
# You can freely distribute/modify this library.
|
||
#
|
||
require 'thread'
|
||
#
|
||
# Adds monitor functionality to an arbitrary object by mixing the module with
|
||
# +include+. For example:
|
||
#
|
||
# require 'monitor'
|
||
#
|
||
# 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
|
||
#
|
||
#
|
||
# In concurrent programming, a monitor is an object or module intended
|
||
# to be used safely by more than one thread. The defining
|
||
# characteristic of a monitor is that its methods are executed with
|
||
# mutual exclusion. That is, at each point in time, at most one thread
|
||
# may be executing any of its methods. This mutual exclusion greatly
|
||
# simplifies reasoning about the implementation of monitors compared
|
||
# to reasoning about parallel code that updates a data structure. Read
|
||
# more about the general principle at
|
||
# Wikimedia[https://secure.wikimedia.org/wikipedia/en/wiki/Monitor_%28synchronization%29].
|
||
#
|
||
# == Examples
|
||
#
|
||
# === Simple object.extend
|
||
#
|
||
# 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.
|
||
#
|
||
# === Simple Class include
|
||
#
|
||
# require 'monitor'
|
||
#
|
||
# class SynchronizedArray < Array
|
||
#
|
||
# include MonitorMixin
|
||
#
|
||
# def initialize(*args)
|
||
# super(*args)
|
||
# end
|
||
#
|
||
# alias :old_shift :shift
|
||
# alias :old_unshift :unshift
|
||
#
|
||
# def shift(n=1)
|
||
# self.synchronize do
|
||
# self.old_shift(n)
|
||
# end
|
||
# end
|
||
#
|
||
# def unshift(item)
|
||
# self.synchronize do
|
||
# self.old_unshift(item)
|
||
# end
|
||
# end
|
||
#
|
||
# # other methods ...
|
||
# end
|
||
#
|
||
# +SynchronizedArray+ implements an +Array+ with synchronized access
|
||
# to items. This +Class+ is implemented as subclass of +Array+ mixin
|
||
# the +MonitorMixin+ module.
|
||
#
|
||
module MonitorMixin
|
||
#
|
||
... | ... | |
private
|
||
# Use <tt>Object#extend(MonitorMixin)</tt> or
|
||
# <tt>Object#include</tt> instead of this constructor. Have look at
|
||
# the examples above to understand how to use this module.
|
||
def initialize(*args)
|
||
super
|
||
mon_initialize
|
||
end
|
||
# Initialize the <tt>MonitorMixin</tt> within an <tt>Object</tt>.
|
||
def mon_initialize
|
||
@mon_owner = nil
|
||
@mon_count = 0
|
||
... | ... | |
end
|
||
end
|
||
# Create a +Monitor+ class if you want to have a lock object for
|
||
# blocks with mutual exclusion.
|
||
#
|
||
# require 'monitor'
|
||
#
|
||
# lock = Monitor.new
|
||
# lock.synchronize do
|
||
# # exclusive access
|
||
# end
|
||
#
|
||
class Monitor
|
||
include MonitorMixin
|
||
alias try_enter try_mon_enter
|