summaryrefslogtreecommitdiff
path: root/lib/thread.rb
diff options
context:
space:
mode:
authorgsinclair <gsinclair@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-01-17 09:30:11 +0000
committergsinclair <gsinclair@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-01-17 09:30:11 +0000
commit94d28746c2ad68fb18e2238f2a27eb782090e453 (patch)
tree902d0c561b138b71b65b9528b066041797e4735f /lib/thread.rb
parentb63bab709abd4698dcf98c168a425daec8d5384d (diff)
Added RDoc comments. Several TODOs remain; see comments at EOF.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3352 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/thread.rb')
-rw-r--r--lib/thread.rb136
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/thread.rb b/lib/thread.rb
index 1a08aa7761..2769c54c3e 100644
--- a/lib/thread.rb
+++ b/lib/thread.rb
@@ -21,6 +21,9 @@ if $DEBUG
Thread.abort_on_exception = true
end
+#
+# FIXME: not documented in Pickaxe or Nutshell.
+#
def Thread.exclusive
_old = Thread.critical
begin
@@ -31,6 +34,27 @@ def Thread.exclusive
end
end
+#
+# +Mutex+ implements a simple semaphore that can be used to coordinate access to
+# shared data from multiple concurrent threads.
+#
+# Example:
+#
+# require 'thread'
+# semaphore = Mutex.new
+#
+# a = Thread.new {
+# semaphore.synchronize {
+# # access shared resource
+# }
+# }
+#
+# b = Thread.new {
+# semaphore.synchronize {
+# # access shared resource
+# }
+# }
+#
class Mutex
def initialize
@waiting = []
@@ -39,10 +63,17 @@ class Mutex
self.taint
end
+ #
+ # Returns +true+ if this lock is currently held by some thread.
+ #
def locked?
@locked
end
+ #
+ # Attempts to obtain the lock and returns immediately. Returns +true+ if the
+ # lock was granted.
+ #
def try_lock
result = false
Thread.critical = true
@@ -54,6 +85,9 @@ class Mutex
result
end
+ #
+ # Attempts to grab the lock and waits if it isn't available.
+ #
def lock
while (Thread.critical = true; @locked)
@waiting.push Thread.current
@@ -64,6 +98,9 @@ class Mutex
self
end
+ #
+ # Releases the lock. Returns +nil+ if ref wasn't locked.
+ #
def unlock
return unless @locked
Thread.critical = true
@@ -82,6 +119,10 @@ class Mutex
self
end
+ #
+ # Obtains a lock, runs the block, and releases the lock when the block
+ # completes. See the example under +Mutex+.
+ #
def synchronize
lock
begin
@@ -91,6 +132,9 @@ class Mutex
end
end
+ #
+ # FIXME: not documented in Pickaxe/Nutshell.
+ #
def exclusive_unlock
return unless @locked
Thread.exclusive do
@@ -107,11 +151,41 @@ class Mutex
end
end
+#
+# +ConditionVariable+ objects augment class +Mutex+. Using condition variables,
+# it is possible to suspend while in the middle of a critical section until a
+# resource becomes available (see the discussion on page 117).
+#
+# Example:
+#
+# require 'thread'
+#
+# mutex = Mutex.new
+# resource = ConditionVariable.new
+#
+# a = Thread.new {
+# mutex.synchronize {
+# # Thread 'a' now needs the resource
+# resource.wait(mutex)
+# # 'a' can now have the resource
+# }
+# }
+#
+# b = Thread.new {
+# mutex.synchronize {
+# # Thread 'b' has finished using the resource
+# resource.signal
+# }
+# }
+#
class ConditionVariable
def initialize
@waiters = []
end
+ #
+ # Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
+ #
def wait(mutex)
mutex.exclusive_unlock do
@waiters.push(Thread.current)
@@ -120,6 +194,9 @@ class ConditionVariable
mutex.lock
end
+ #
+ # Wakes up the first thread in line waiting for this lock.
+ #
def signal
begin
t = @waiters.shift
@@ -129,6 +206,9 @@ class ConditionVariable
end
end
+ #
+ # Wakes up all threads waiting for this lock.
+ #
def broadcast
waiters0 = nil
Thread.exclusive do
@@ -144,7 +224,16 @@ class ConditionVariable
end
end
+#
+# This class provides a way to communicate data between threads.
+#
+# TODO: an example (code or English) would really help here. How do you set up
+# a queue between two threads?
+#
class Queue
+ #
+ # Creates a new queue.
+ #
def initialize
@que = []
@waiting = []
@@ -153,6 +242,9 @@ class Queue
self.taint
end
+ #
+ # Pushes +obj+ to the queue.
+ #
def push(obj)
Thread.critical = true
@que.push obj
@@ -172,6 +264,11 @@ class Queue
alias << push
alias enq push
+ #
+ # Retrieves data from the queue. If the queue is empty, the calling thread is
+ # suspended until data is pushed onto the queue. If +non_block+ is true, the
+ # thread isn't suspended, and an exception is raised.
+ #
def pop(non_block=false)
while (Thread.critical = true; @que.empty?)
raise ThreadError, "queue empty" if non_block
@@ -185,27 +282,50 @@ class Queue
alias shift pop
alias deq pop
+ #
+ # Returns +true+ is the queue is empty.
+ #
def empty?
@que.empty?
end
+ #
+ # Removes all objects from the queue.
+ #
def clear
@que.clear
end
+ #
+ # Returns the length of the queue.
+ #
def length
@que.length
end
+
+ #
+ # Alias of length.
+ #
def size
length
end
+ #
+ # Returns the number of threads waiting on the queue.
+ #
def num_waiting
@waiting.size
end
end
+#
+# This class represents queues of specified size capacity. The +push+ operation
+# may be blocked if the capacity is full.
+#
class SizedQueue<Queue
+ #
+ # Creates a fixed-length queue with a maximum size of +max+.
+ #
def initialize(max)
raise ArgumentError, "queue size must be positive" unless max > 0
@max = max
@@ -214,10 +334,16 @@ class SizedQueue<Queue
super()
end
+ #
+ # Returns the maximum size of the queue.
+ #
def max
@max
end
+ #
+ # Sets the maximum size of the queue.
+ #
def max=(max)
Thread.critical = true
if max <= @max
@@ -277,3 +403,13 @@ class SizedQueue<Queue
@waiting.size + @queue_wait.size
end
end
+
+# Documentation comments:
+# - SizedQueue #push and #pop deserve some documentation, as they are different
+# from the Queue implementations.
+# - Some methods are not documented in Pickaxe/Nutshell, and are therefore not
+# documented here. See FIXME notes.
+# - Reference to Pickaxe page numbers should be replaced with either a section
+# name or a summary.
+# - How do you document aliases?
+# - How do you make RDoc inherit documentation from superclass?