5 Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
7 This library is distributed under the terms of the Ruby license.
8 You can freely distribute/modify this library.
12 This is a simple example.
17 buf.extend(MonitorMixin)
18 empty_cond = buf.new_cond
24 empty_cond.wait_while { buf.empty? }
31 while line = ARGF.gets
38 The consumer thread waits for the producer thread to push a line
39 to buf while buf.empty?, and the producer thread (main thread)
40 reads a line from ARGF and push it to buf, then call
48 # Adds monitor functionality to an arbitrary object by mixing the module with
49 # +include+. For example:
54 # buf.extend(MonitorMixin)
55 # empty_cond = buf.new_cond
61 # empty_cond.wait_while { buf.empty? }
68 # while line = ARGF.gets
75 # The consumer thread waits for the producer thread to push a line
76 # to buf while buf.empty?, and the producer thread (main thread)
77 # reads a line from ARGF and push it to buf, then call
82 # FIXME: This isn't documented in Nutshell.
84 # Since MonitorMixin.new_cond returns a ConditionVariable, and the example
85 # above calls while_wait and signal, this class should be documented.
87 class ConditionVariable
88 class Timeout < Exception; end
90 def wait(timeout = nil)
92 raise NotImplementedError, "timeout is not implemented yet"
94 @monitor.send(:mon_check_owner)
95 count = @monitor.send(:mon_exit_for_cond)
97 @cond.wait(@monitor.instance_variable_get("@mon_mutex"))
100 @monitor.send(:mon_enter_for_cond, count)
117 @monitor.send(:mon_check_owner)
122 @monitor.send(:mon_check_owner)
127 raise NotImplementedError
132 def initialize(monitor)
134 @cond = ::ConditionVariable.new
138 def self.extend_object(obj)
140 obj.send(:mon_initialize)
144 # Attempts to enter exclusive section. Returns +false+ if lock fails.
147 if @mon_owner != Thread.current
148 unless @mon_mutex.try_lock
151 @mon_owner = Thread.current
156 # For backward compatibility
157 alias try_mon_enter mon_try_enter
160 # Enters exclusive section.
163 if @mon_owner != Thread.current
165 @mon_owner = Thread.current
171 # Leaves exclusive section.
183 # Enters exclusive section and executes the block. Leaves the exclusive
184 # section automatically when the block exits. See example under
195 alias synchronize mon_synchronize
198 # FIXME: This isn't documented in Nutshell.
201 return ConditionVariable.new(self)
206 def initialize(*args)
214 @mon_mutex = Mutex.new
218 if @mon_owner != Thread.current
219 raise ThreadError, "current thread not owner"
223 def mon_enter_for_cond(count)
224 @mon_owner = Thread.current
228 def mon_exit_for_cond
238 alias try_enter try_mon_enter
239 alias enter mon_enter
244 # Documentation comments:
245 # - All documentation comes from Nutshell.
246 # - MonitorMixin.new_cond appears in the example, but is not documented in
248 # - All the internals (internal modules Accessible and Initializable, class
249 # ConditionVariable) appear in RDoc. It might be good to hide them, by
250 # making them private, or marking them :nodoc:, etc.
251 # - The entire example from the RD section at the top is replicated in the RDoc
252 # comment for MonitorMixin. Does the RD section need to remain?
253 # - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but
255 # - mon_owner is in Nutshell, but appears as an accessor in a separate module
256 # here, so is hard/impossible to RDoc. Some other useful accessors
257 # (mon_count and some queue stuff) are also in this module, and don't appear
258 # directly in the RDoc output.
259 # - in short, it may be worth changing the code layout in this file to make the
260 # documentation easier