Moved up section on mutexes and condition variables. Added critical
authorMarius Vollmer <mvo@zagadka.de>
Mon, 7 Mar 2005 21:49:43 +0000 (21:49 +0000)
committerMarius Vollmer <mvo@zagadka.de>
Mon, 7 Mar 2005 21:49:43 +0000 (21:49 +0000)
"Critical Sections" section.

doc/ref/api-scheduling.texi

index cbd9180..7e5a29b 100644 (file)
@@ -17,11 +17,12 @@ reviewed and largely reorganized.]
 * Asyncs::                      Asynchronous procedure invocation.
 * Continuation Barriers::       Protection from non-local control flow.
 * Threads::                     Multiple threads of execution.
+* Mutexes and Condition Variables:: Synchronization primitives.
 * Blocking::                    How to block properly in guile mode.
+* Critical Sections::           Avoiding concurrency and reentries.
 * Fluids and Dynamic States::   Thread-local variables, etc.
 * Futures::                     Delayed execution in new threads.
 * Parallel Forms::              Parallel execution of forms.
-* Mutexes and Condition Variables:: Synchronization primitives.
 @end menu
 
 
@@ -302,6 +303,147 @@ Evaluate forms @var{first} and @var{rest} in a new thread formed by
 the error to the current error port.
 @end deffn
 
+@node Mutexes and Condition Variables
+@subsection Mutexes and Condition Variables
+@cindex mutex
+@cindex condition variable
+
+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 in Guile, ``standard'' and
+``recursive''.  They're created by @code{make-mutex} and
+@code{make-recursive-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 {C Function} scm_make_mutex ()
+Return a new standard mutex.  It is initially unlocked.
+@end deffn
+
+@deffn {Scheme Procedure} make-recursive-mutex
+@deffnx {C Function} scm_make_recursive_mutex ()
+Create a new recursive mutex.  It is initialloy unlocked.
+@end deffn
+
+@deffn {Scheme Procedure} lock-mutex mutex
+@deffnx {C Function} scm_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}), and error is signalled if
+the thread has itself already locked @var{mutex}.
+
+For a recursive mutex (@code{make-recursive-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
+
+@deftypefn {C Function} void scm_frame_lock_mutex (SCM mutex)
+Arrange for @var{mutex} to be locked whenever the current frame is
+entered and to be unlocked when it is exited.
+@end deftypefn
+
+@deffn {Scheme Procedure} try-mutex mx
+@deffnx {C Function} scm_try_mutex (mx)
+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
+@deffnx {C Function} scm_unlock_mutex (mutex)
+Unlock @var{mutex}.  An error is signalled if @var{mutex} is not
+locked by the calling thread.
+@end deffn
+
+@deffn {Scheme Procedure} make-condition-variable
+@deffnx {C Function} scm_make_condition_variable ()
+Return a new condition variable.
+@end deffn
+
+@deffn {Scheme Procedure} wait-condition-variable condvar mutex [time]
+@deffnx {C Function} scm_wait_condition_variable (condvar, mutex, time)
+Wait until @var{condvar} has been signalled.  While waiting,
+@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and
+is locked again when this function returns.  When @var{time} is given,
+it specifies a point in time where the waiting should be aborted.  It
+can be either a integer as returned by @code{current-time} or a pair
+as returned by @code{gettimeofday}.  When the waiting is aborted,
+@code{#f} is returned.  When the condition variable has in fact been
+signalled, @code{#t} is returned.  The mutex is re-locked in any case
+before @code{wait-condition-variable} returns.
+
+When a system async is activated for a thread that is blocked in a
+call to @code{wait-condition-variable}, the waiting is interrupted,
+the mutex is locked, and the async is executed.  When the async
+returns, the mutex is unlocked again and the waiting is resumed.  When
+the thread block while re-acquiring the mutex, execution of asyncs is
+blocked.
+@end deffn
+
+@deffn {Scheme Procedure} signal-condition-variable condvar
+@deffnx {C Function} scm_signal_condition_variable (condvar)
+Wake up one thread that is waiting for @var{condvar}.
+@end deffn
+
+@deffn {Scheme Procedure} broadcast-condition-variable condvar
+@deffnx {C Function} scm_broadcast_condition_variable (condvar)
+Wake up all threads that are waiting for @var{condvar}.
+@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
+
+
 @node Blocking
 @subsection Blocking in Guile Mode
 
@@ -364,6 +506,51 @@ delivery of a system async causes this function to be interrupted.
 @end deftypefn
 
 
+@node Critical Sections
+@subsection Critical Sections
+
+@deffn  {C Macro} SCM_CRITICAL_SECTION_START
+@deffnx {C Macro} SCM_CRITICAL_SECTION_END
+These two macros can be used to delimit a critical section.
+Syntactically, they are both statements and need to be followed
+immediately by a semicolon.
+
+Executing @code{SCM_CRITICAL_SECTION_START} will lock a recursive
+mutex and block the executing of system asyncs.  Executing
+@code{SCM_CRITICAL_SECTION_END} will unblock the execution of system
+asyncs and unlock the mutex.  Thus, the code that executes between
+these two macros can only be executed in one thread at any one time
+and no system asyncs will run.  However, because the mutex is a
+recursive one, the code might still be reentered by the same thread.
+You must either allow for this or avoid it, both by careful coding.
+
+On the other hand, critical sections delimited with these macros can
+be nested since the mutex is recursive.
+
+You must make sure that for each @code{SCM_CRITICAL_SECTION_START},
+the corresponding @code{SCM_CRITICAL_SECTION_END} is always executed.
+This means that no non-local exit (such as a signalled error) might
+happen, for example.
+@end deffn
+
+@deftypefn {C Function} void scm_frame_critical_section (SCM mutex)
+Call @code{scm_frame_lock_mutex} on @var{mutex} and call
+@code{scm_frame_block_asyncs}.  When @var{mutex} is false, a recursive
+mutex provided by Guile is used instead.
+
+The effect of a call to @code{scm_frame_critical_section} is that the
+current frame (@pxref{Frames}) turns into a critical section.  Because
+of the locked mutex, no second thread can enter it concurrently and
+because of the blocked asyncs, no system async can reenter it from the
+current thread.
+
+When the current thread reenters the critical section anyway, the kind
+of @var{mutex} determines what happens: When @var{mutex} is recursive,
+the reentry is allowed.  When it is a normal mutex, an error is
+signalled.
+@end deftypefn
+
+
 @node Fluids and Dynamic States
 @subsection Fluids and Dynamic States
 
@@ -634,141 +821,6 @@ completed, it doesn't need to wait for all to finish.
 @end deffn
 
 
-@node Mutexes and Condition Variables
-@subsection Mutexes and Condition Variables
-@cindex mutex
-@cindex condition variable
-
-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 in Guile, ``standard'' and
-``recursive''.  They're created by @code{make-mutex} and
-@code{make-recursive-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 {C Function} scm_make_mutex ()
-Return a new standard mutex.  It is initially unlocked.
-@end deffn
-
-@deffn {Scheme Procedure} make-recursive-mutex
-@deffnx {C Function} scm_make_recursive_mutex ()
-Create a new recursive mutex.  It is initialloy unlocked.
-@end deffn
-
-@deffn {Scheme Procedure} lock-mutex mutex
-@deffnx {C Function} scm_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}), and error is signalled if
-the thread has itself already locked @var{mutex}.
-
-For a recursive mutex (@code{make-recursive-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 mx
-@deffnx {C Function} scm_try_mutex (mx)
-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
-@deffnx {C Function} scm_unlock_mutex (mutex)
-Unlock @var{mutex}.  An error is signalled if @var{mutex} is not
-locked by the calling thread.
-@end deffn
-
-@deffn {Scheme Procedure} make-condition-variable
-@deffnx {C Function} scm_make_condition_variable ()
-Return a new condition variable.
-@end deffn
-
-@deffn {Scheme Procedure} wait-condition-variable condvar mutex [time]
-@deffnx {C Function} scm_wait_condition_variable (condvar, mutex, time)
-Wait until @var{condvar} has been signalled.  While waiting,
-@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and
-is locked again when this function returns.  When @var{time} is given,
-it specifies a point in time where the waiting should be aborted.  It
-can be either a integer as returned by @code{current-time} or a pair
-as returned by @code{gettimeofday}.  When the waiting is aborted,
-@code{#f} is returned.  When the condition variable has in fact been
-signalled, @code{#t} is returned.  The mutex is re-locked in any case
-before @code{wait-condition-variable} returns.
-
-When a system async is activated for a thread that is blocked in a
-call to @code{wait-condition-variable}, the waiting is interrupted,
-the mutex is locked, and the async is executed.  When the async
-returns, the mutex is unlocked again and the waiting is resumed.  When
-the thread block while re-acquiring the mutex, execution of asyncs is
-blocked.
-@end deffn
-
-@deffn {Scheme Procedure} signal-condition-variable condvar
-@deffnx {C Function} scm_signal_condition_variable (condvar)
-Wake up one thread that is waiting for @var{condvar}.
-@end deffn
-
-@deffn {Scheme Procedure} broadcast-condition-variable condvar
-@deffnx {C Function} scm_broadcast_condition_variable (condvar)
-Wake up all threads that are waiting for @var{condvar}.
-@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
-
 
 @c Local Variables:
 @c TeX-master: "guile.texi"