1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-10 14:00:21 +02:00

Moved up section on mutexes and condition variables. Added critical

"Critical Sections" section.
This commit is contained in:
Marius Vollmer 2005-03-07 21:49:43 +00:00
parent 32106a5ded
commit 2567692aeb

View 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"