* Fluids:: Thread-local variables.
* Futures:: Delayed execution in new threads.
* Parallel Forms:: Parallel execution of forms.
+* Mutexes:: Synchronization primitives.
@end menu
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)
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.
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
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
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)
@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: