summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Ryde <user42@zip.com.au>2004-08-14 01:02:37 +0000
committerKevin Ryde <user42@zip.com.au>2004-08-14 01:02:37 +0000
commit3cf066df9b59d7fec390168f09da1a4aaa8d72e7 (patch)
treebb17987cd766b5318cbddfe897aa1ea68a8f087a
parent02d9c82a027e1135d22da1efbba02a2ad2cca83d (diff)
downloadguile-3cf066df9b59d7fec390168f09da1a4aaa8d72e7.tar.gz
(Mutexes): New datatype-centric section, adding
fair mutexes and collecting up material from ... (Low level thread primitives, Higher level thread procedures, C level thread interface): ... these nodes.
-rw-r--r--doc/ref/api-scheduling.texi249
1 files changed, 153 insertions, 96 deletions
diff --git a/doc/ref/api-scheduling.texi b/doc/ref/api-scheduling.texi
index c3aef48a0..f85ea4aaa 100644
--- a/doc/ref/api-scheduling.texi
+++ b/doc/ref/api-scheduling.texi
@@ -20,6 +20,7 @@ reviewed and largely reorganized.]
* Fluids:: Thread-local variables.
* Futures:: Delayed execution in new threads.
* Parallel Forms:: Parallel execution of forms.
+* Mutexes:: Synchronization primitives.
@end menu
@@ -31,10 +32,10 @@ Arbiters are synchronization objects, they can be used by threads to
control access to a shared resource. An arbiter can be locked to
indicate a resource is in use, and unlocked when done.
-An arbiter is like a light-weight mutex (@pxref{Low level thread
-primitives}). It uses less memory and may be a little faster, but
-there's no way for a thread to block waiting on an arbiter, it can
-only test and get the status returned.
+An arbiter is like a light-weight mutex (@pxref{Mutexes}). It uses
+less memory and may be faster, but there's no way for a thread to
+block waiting on an arbiter, it can only test and get the status
+returned.
@deffn {Scheme Procedure} make-arbiter name
@deffnx {C Function} scm_make_arbiter (name)
@@ -351,40 +352,6 @@ If one or more threads are waiting to execute, calling yield forces an
immediate context switch to one of them. Otherwise, yield has no effect.
@end deffn
-@c begin (texi-doc-string "guile" "make-mutex")
-@deffn {Scheme Procedure} make-mutex
-Create a new mutex object.
-@end deffn
-
-@c begin (texi-doc-string "guile" "lock-mutex")
-@deffn {Scheme Procedure} lock-mutex mutex
-Lock @var{mutex}. If the mutex is already locked, the calling thread
-blocks until the mutex becomes available. The function returns when
-the calling thread owns the lock on @var{mutex}. Locking a mutex that
-a thread already owns will succeed right away and will not block the
-thread. That is, Guile's mutexes are @emph{recursive}.
-
-When a system async is activated for a thread that is blocked in a
-call to @code{lock-mutex}, the waiting is interrupted and the async is
-executed. When the async returns, the waiting is resumed.
-@end deffn
-
-@deffn {Scheme Procedure} try-mutex mutex
-Try to lock @var{mutex}. If the mutex is already locked by someone
-else, return @code{#f}. Else lock the mutex and return @code{#t}.
-@end deffn
-
-@c begin (texi-doc-string "guile" "unlock-mutex")
-@deffn {Scheme Procedure} unlock-mutex mutex
-Unlocks @var{mutex} if the calling thread owns the lock on
-@var{mutex}. Calling unlock-mutex on a mutex not owned by the current
-thread results in undefined behaviour. Once a mutex has been unlocked,
-one thread blocked on @var{mutex} is awakened and grabs the mutex
-lock. Every call to @code{lock-mutex} by this thread must be matched
-with a call to @code{unlock-mutex}. Only the last call to
-@code{unlock-mutex} will actually unlock the mutex.
-@end deffn
-
@c begin (texi-doc-string "guile" "make-condition-variable")
@deffn {Scheme Procedure} make-condition-variable
Make a new condition variable.
@@ -425,7 +392,7 @@ Wake up all threads that are waiting for @var{cv}.
Higher level thread procedures are available by loading the
@code{(ice-9 threads)} module. These provide standardized
-thread creation and mutex interaction.
+thread creation.
@deffn macro make-thread proc [args@dots{}]
Apply @var{proc} to @var{args} in a new thread formed by
@@ -439,31 +406,12 @@ Evaluate forms @var{first} and @var{rest} in a new thread formed by
the error to the current error port.
@end deffn
-@deffn macro with-mutex m [body@dots{}]
-Lock mutex @var{m}, evaluate @var{body}, and then unlock @var{m}.
-These sub-operations form the branches of a @code{dynamic-wind}.
-@end deffn
-
-@deffn macro monitor body@dots{}
-Evaluate @var{body}, with a mutex locked so only one thread can
-execute that code at any one time. Each @code{monitor} form has its
-own private mutex and the locking is done as per @code{with-mutex}
-above. The return value is the return from the last form in
-@var{body}.
-
-The term ``monitor'' comes from operating system theory, where it
-means a particular bit of code managing access to some resource and
-which only ever executes on behalf of one process at any one time.
-@end deffn
-
@node C level thread interface
@subsubsection C level thread interface
-You can create and manage threads, mutexes, and condition variables
-with the C versions of the primitives above. For example, you can
-create a mutex with @code{scm_make_mutex} and lock it with
-@code{scm_lock_mutex}. In addition to these primitives there is also
-a second set of primitives for threading related things. These
+You can create and manage threads
+with the C versions of the primitives above.
+These
functions and data types are only available from C and can not be
mixed with the first set from above. However, they might be more
efficient and can be used in situations where Scheme data types are
@@ -539,47 +487,13 @@ might have been detached by the time it terminates.
Return the handle of the calling thread.
@end deftypefn
-@deftp {C Data Type} scm_t_mutex
-This data type represents a mutex, to be used with scm_mutex_init,
-etc.
-@end deftp
-
-@deftypefn {C Function} void scm_mutex_init (scm_t_mutex *m)
-Initialize the mutex structure pointed to by @var{m}.
-@end deftypefn
-
-@deftypefn {C Function} void scm_mutex_destroy (scm_t_mutex *m)
-Deallocate all resources associated with @var{m}.
-@end deftypefn
-
-@deftypefn {C Function} void scm_mutex_lock (scm_t_mutex *m)
-Lock the mutex @var{m}. When it is already locked by a different
-thread, wait until it becomes available. Locking a mutex that is
-already locked by the current threads is not allowd and results in
-undefined behavior. The mutices are not guaranteed to be fair. That
-is, a thread that attempts a lock after yourself might be granted it
-before you.
-@end deftypefn
-
-@deftypefn {C Function} int scm_mutex_trylock (scm_t_mutex *m)
-Lock @var{m} as with @code{scm_mutex_lock} but don't wait when this
-does succeed immediately. Returns non-zero when the mutex could in
-fact be locked , and zero when it is already locked by some other
-thread.
-@end deftypefn
-
-@deftypefn {C Function} void scm_mutex_unlock (scm_t_mutex *m)
-Unlock the mutex @var{m}. The mutex must have been locked by the
-current thread, else the behavior is undefined.
-@end deftypefn
-
@deftp {C Data Type} scm_t_cond
This data type represents a condition variable, to be used with
scm_cond_init, etc.
@end deftp
@deftypefn {C Function} void scm_cond_init (scm_t_cond *c)
-Initialize the mutex structure pointed to by @var{c}.
+Initialize the condition variable structure pointed to by @var{c}.
@end deftypefn
@deftypefn {C Function} void scm_cond_destroy (scm_t_cond *c)
@@ -858,6 +772,149 @@ completed, it doesn't need to wait for all to finish.
@end deffn
+@node Mutexes
+@subsection Mutexes
+@cindex mutex
+
+A mutex is a thread synchronization object, it can be used by threads
+to control access to a shared resource. A mutex can be locked to
+indicate a resource is in use, and other threads can then block on the
+mutex to wait for the resource (or can just test and do something else
+if not available). ``Mutex'' is short for ``mutual exclusion''.
+
+There are two types of mutexes, ``standard'' and ``fair''. They're
+created by @code{make-mutex} and @code{make-fair-mutex} respectively,
+the operation functions are then common to both.
+
+Note that for both types of mutex there's no protection against a
+``deadly embrace''. For instance if one thread has locked mutex A and
+is waiting on mutex B, but another thread owns B and is waiting on A,
+then an endless wait will occur (in the current implementation).
+Acquiring requisite mutexes in a fixed order (like always A before B)
+in all threads is one way to avoid such problems.
+
+@sp 1
+@deffn {Scheme Procedure} make-mutex
+@deffnx {Scheme Procedure} make-fair-mutex
+Return a new mutex object.
+
+@code{make-mutex} creates a standard mutex. This is fast, but its
+features are restricted. Recursive locking (multiple lock calls by
+one thread) is not permitted, and an unlock can be done only when
+already locked and only by the owning thread. When multiple threads
+are blocked waiting to acquire the mutex, it's unspecified which will
+get it next.
+
+@code{make-fair-mutex} creates a fair mutex. This has more features
+and error checking. Recursive locking is allowed, a given thread can
+make multiple lock calls and the mutex is released when a balancing
+number of unlocks are done. Other threads blocked waiting to acquire
+the mutex form a queue and the one waiting longest will be the next to
+acquire it.
+@end deffn
+
+@deffn {Scheme Procedure} lock-mutex mutex
+Lock @var{mutex}. If the mutex is already locked by another thread
+then block and return only when @var{mutex} has been acquired.
+
+For standard mutexes (@code{make-mutex}), if the thread has itself
+already locked @var{mutex} it must not call @code{lock-mutex} on it a
+further time. Behaviour is unspecified if this is done.
+
+For a fair mutex (@code{make-fair-mutex}), if the thread has itself
+already locked @var{mutex}, then a further @code{lock-mutex} call
+increments the lock count. An additional @code{unlock-mutex} will be
+required to finally release.
+
+When a system async (@pxref{System asyncs}) is activated for a thread
+blocked in @code{lock-mutex}, the wait is interrupted and the async is
+executed. When the async returns the wait resumes.
+@end deffn
+
+@deffn {Scheme Procedure} try-mutex mutex
+Try to lock @var{mutex} as per @code{lock-mutex}. If @var{mutex} can
+be acquired immediately then this is done and the return is @code{#t}.
+If @var{mutex} is locked by some other thread then nothing is done and
+the return is @code{#f}.
+@end deffn
+
+@deffn {Scheme Procedure} unlock-mutex mutex
+Unlock @var{mutex}.
+
+For a standard mutex (@code{make-mutex}), if @var{mutex} is not locked
+by the calling thread then behaviour is unspecified.
+
+For a fair mutex (@code{make-fair-mutex}), if @var{mutex} is not
+locked by the calling thread then an error is thrown.
+@end deffn
+
+@sp 1
+The following are higher level operations on mutexes. These are
+available from
+
+@example
+(use-modules (ice-9 threads))
+@end example
+
+@deffn macro with-mutex mutex [body@dots{}]
+Lock @var{mutex}, evaluate the @var{body} forms, then unlock
+@var{mutex}. The return value is the return from the last @var{body}
+form.
+
+The lock, body and unlock form the branches of a @code{dynamic-wind}
+(@pxref{Dynamic Wind}), so @var{mutex} is automatically unlocked if an
+error or new continuation exits @var{body}, and is re-locked if
+@var{body} is re-entered by a captured continuation.
+@end deffn
+
+@deffn macro monitor body@dots{}
+Evaluate the @var{body} forms, with a mutex locked so only one thread
+can execute that code at any one time. The return value is the return
+from the last @var{body} form.
+
+Each @code{monitor} form has its own private mutex and the locking and
+evaluation is as per @code{with-mutex} above. A standard mutex
+(@code{make-mutex}) is used, which means @var{body} must not
+recursively re-enter the @code{monitor} form.
+
+The term ``monitor'' comes from operating system theory, where it
+means a particular bit of code managing access to some resource and
+which only ever executes on behalf of one process at any one time.
+@end deffn
+
+@sp 1
+The following provide access to standard mutexes from C code.
+
+@deftp {C Data Type} scm_t_mutex
+A mutex, to be used with @code{scm_mutex_init}, etc.
+@end deftp
+
+@deftypefn {C Function} void scm_mutex_init (scm_t_mutex *m)
+Initialize the mutex structure pointed to by @var{m}.
+@end deftypefn
+
+@deftypefn {C Function} void scm_mutex_destroy (scm_t_mutex *m)
+Free all resources associated with @var{m}.
+@end deftypefn
+
+@deftypefn {C Function} void scm_mutex_lock (scm_t_mutex *m)
+Lock the mutex @var{m}. This is as per @code{lock-mutex} above on a
+standard mutex.
+@end deftypefn
+
+@deftypefn {C Function} int scm_mutex_trylock (scm_t_mutex *m)
+Attempt to lock mutex @var{m}, as per @code{scm_mutex_lock}. If
+@var{m} is unlocked then this is done and the return is non-zero. If
+@var{m} is already locked by another thread then do nothing and return
+zero.
+@end deftypefn
+
+@deftypefn {C Function} void scm_mutex_unlock (scm_t_mutex *m)
+Unlock the mutex @var{m}. The mutex must have been locked by the
+current thread, otherwise the behavior is undefined.
+@end deftypefn
+
+
@c Local Variables:
@c TeX-master: "guile.texi"
@c End: