documentation for thread support (stolen from Jan's SWI docs).
git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@1021 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
This commit is contained in:
parent
cd3142c211
commit
dbe36978b6
291
docs/yap.tex
291
docs/yap.tex
@ -8,7 +8,7 @@
|
||||
@c @setchapternewpage odd
|
||||
@c %**end of header
|
||||
|
||||
@set VERSION: 4.5.2
|
||||
@set VERSION 4.5.2
|
||||
@set EDITION 4.2.3
|
||||
@set UPDATED January 2002
|
||||
|
||||
@ -7737,7 +7737,7 @@ mailing-list.
|
||||
@findex splay_access/5
|
||||
@snindex splay_access/5
|
||||
@cnindex splay_access/5
|
||||
If item @var{Key} is in tree @var{Tree}, return its @value{Val} and
|
||||
If item @var{Key} is in tree @var{Tree}, return its @var{Val} and
|
||||
unify @var{Return} with @code{true}. Otherwise unify @var{Return} with
|
||||
@code{null}. The variable @var{NewTree} unifies with the new tree.
|
||||
|
||||
@ -12124,13 +12124,13 @@ Logtalk documentation is included in the Logtalk directory. For the
|
||||
latest news, please see the URL @url{http://www.logtalk.org/}.
|
||||
|
||||
@node Threads, Parallelism, Logtalk, Extensions
|
||||
@chapter Parallelism
|
||||
@chapter Threads
|
||||
|
||||
YAP implements a SWI-Prolog compatible multithreading
|
||||
library. Like in SWI-Prolog, Prolog threads have their own stacks and
|
||||
only share the Prolog \emph{heap}: predicates, records, flags and other
|
||||
only share the Prolog @emph{heap}: predicates, records, flags and other
|
||||
global non-backtrackable data. The package is based on the POSIX thread
|
||||
standard \cite{Butenhof:1997:PPT} used on most popular systems except
|
||||
standard (Butenhof:1997:PPT) used on most popular systems except
|
||||
for MS-Windows.
|
||||
|
||||
@comment On Windows it uses the
|
||||
@ -12140,15 +12140,19 @@ for MS-Windows.
|
||||
|
||||
@menu
|
||||
Subnodes of Threads
|
||||
* Creating and destroying Prolog threads::
|
||||
* Monitoring threads::
|
||||
* Thread communication::
|
||||
* Thread synchronisation::
|
||||
* Creating and Destroying Prolog Threads::
|
||||
* Monitoring Threads::
|
||||
* Thread Communication::
|
||||
* Thread Synchronisation::
|
||||
|
||||
Subnodes of Thread Communication
|
||||
* Message Queues::
|
||||
* Signalling Threads::
|
||||
* Threads and Dynamic Predicates::
|
||||
@end menu
|
||||
|
||||
@node Creating and destroying Prolog threads, Monitoring Threads, ,Threads
|
||||
@section Creating and destroying Prolog threads
|
||||
@node Creating and Destroying Prolog Threads, Monitoring Threads, ,Threads
|
||||
@section Creating and Destroying Prolog Threads
|
||||
|
||||
@table @code
|
||||
|
||||
@ -12166,12 +12170,12 @@ thread-identifier of the created thread is unified to @var{Id}.
|
||||
@item stack
|
||||
Set the limit in K-Bytes to which the Prolog stacks of
|
||||
this thread may grow. If omited, the limit of the calling thread is
|
||||
used. See also the \cmdlineoption{-s} commandline option.
|
||||
used. See also the commandline @code{-S} option.
|
||||
|
||||
@item trail
|
||||
Set the limit in K-Bytes to which the trail stack of this thread may
|
||||
grow. If omited, the limit of the calling thread is used. See also the
|
||||
\cmdlineoption{-t} commandline option.
|
||||
commandline option @code{-T}.
|
||||
|
||||
@item alias
|
||||
Associate an alias-name with the thread. This named may be used to
|
||||
@ -12188,7 +12192,7 @@ after a detached thread finishes or a normal thread has been joined.
|
||||
See also @code{thread_join/2} and @code{thread_detach/1}.
|
||||
@end table
|
||||
|
||||
The @var{Goal} argument is \emph{copied} to the new Prolog engine.
|
||||
The @var{Goal} argument is @emph{copied} to the new Prolog engine.
|
||||
This implies further instantiation of this term in either thread does
|
||||
not have consequences for the other thread: Prolog threads do not share
|
||||
data from their stacks.
|
||||
@ -12228,8 +12232,8 @@ The goal has failed.
|
||||
exception. See @code{print_message/2} to turn system exceptions into
|
||||
readable messages.
|
||||
|
||||
@item exited(@var{Term)
|
||||
The thread is terminated on thread_exit/1 using the argument @var{Term}.
|
||||
@item exited(@var{Term})
|
||||
The thread is terminated on @code{thread_exit/1} using the argument @var{Term}.
|
||||
@end table
|
||||
|
||||
|
||||
@ -12237,7 +12241,7 @@ The thread is terminated on thread_exit/1 using the argument @var{Term}.
|
||||
@findex thread_detach/1
|
||||
@snindex thread_detach/1
|
||||
@cnindex thread_detach/1
|
||||
Switch thread into detached-state (see \code{detached} option at
|
||||
Switch thread into detached-state (see @code{detached} option at
|
||||
@code{thread_create/3} at runtime. @var{Id} is the identifier of the thread
|
||||
placed in detached state.
|
||||
|
||||
@ -12255,7 +12259,7 @@ inspected.
|
||||
@cnindex thread_exit/1
|
||||
Terminates the thread immediately, leaving @code{exited(@var{Term})} as
|
||||
result-state for @code{thread_join/2}. If the thread has the attribute
|
||||
\term{detached}{true} it terminates, but its exit status cannot be
|
||||
@code{detached} @code{true} it terminates, but its exit status cannot be
|
||||
retrieved using @code{thread_join/2} making the value of @var{Term}
|
||||
irrelevant. The Prolog stacks and C-thread are reclaimed.
|
||||
|
||||
@ -12284,8 +12288,8 @@ and succeeds silently.
|
||||
@end table
|
||||
|
||||
|
||||
@node Monitoring threads, Thread Communication,Creating and destroying Prolog threads,Threads
|
||||
@section Monitoring threads
|
||||
@node Monitoring Threads, Thread Communication,Creating and Destroying Prolog Threads,Threads
|
||||
@section Monitoring Threads
|
||||
|
||||
Normal multi-threaded applications should not need these the predicates
|
||||
from this section because almost any usage of these predicates is
|
||||
@ -12302,7 +12306,6 @@ These predicates are provided for diagnosis and monitoring tasks.
|
||||
@findex current_thread/2
|
||||
@snindex current_thread/2
|
||||
@cnindex current_thread/2
|
||||
\predicate{current_thread}{2}{?Id, ?Status}
|
||||
Enumerates identifiers and status of all currently known threads.
|
||||
Calling current_thread/2 does not influence any thread. See also
|
||||
@code{thread_join/2}. For threads that have an alias-name, this name is
|
||||
@ -12343,7 +12346,6 @@ stacks and CPU time yield different values for each thread.
|
||||
@findex mutex_statistics/0
|
||||
@snindex mutex_statistics/0
|
||||
@cnindex mutex_statistics/0
|
||||
\predicate{mutex_statistics}{0}{}
|
||||
Print usage statistics on internal mutexes and mutexes associated
|
||||
with dynamic predicates. For each mutex two numbers are printed:
|
||||
the number of times the mutex was acquired and the number of
|
||||
@ -12355,103 +12357,121 @@ close to zero on single-CPU hardware.
|
||||
@end table
|
||||
|
||||
|
||||
@node Thread Communication, ,Monitoring threads, Threads
|
||||
@node Thread Communication, Thread Synchronisation, Monitoring Threads, Threads
|
||||
@section Thread communication
|
||||
|
||||
\subsection{Message queues} \label{sec:msgqueue}
|
||||
@menu
|
||||
Subnodes of Thread Communication
|
||||
* Message Queues::
|
||||
* Signalling Threads::
|
||||
* Threads and Dynamic Predicates::
|
||||
@end menu
|
||||
|
||||
@node Message Queues, Signalling Threads, ,Thread Communication
|
||||
@subsection Message Queues
|
||||
|
||||
Prolog threads can exchange data using dynamic predicates, database
|
||||
records, and other globally shared data. These provide no suitable means
|
||||
to wait for data or a condition as they can only be checked in an
|
||||
expensive polling loop. \jargon{Message queues} provide a means for
|
||||
expensive polling loop. @emph{Message queues} provide a means for
|
||||
threads to wait for data or conditions without using the CPU.
|
||||
|
||||
Each thread has a message-queue attached to it that is identified
|
||||
by the thread. Additional queues are created using
|
||||
message_queue_create/2.
|
||||
@code{message_queue_create/2}.
|
||||
|
||||
@table @code
|
||||
\predicate{thread_send_message}{2}{+QueueOrThreadId, +Term}
|
||||
@item thread_send_message(+@var{QueueOrThreadId}, +@var{Term})
|
||||
@findex thread_send_message/2
|
||||
@snindex thread_send_message/2
|
||||
@cnindex thread_send_message/2
|
||||
Place @var{Term} in the given queue or default queue of the indicated
|
||||
thread (which can even be the message queue of itself (see
|
||||
thread_self/1). Any term can be placed in a message queue, but note that
|
||||
@code{thread_self/1}). Any term can be placed in a message queue, but note that
|
||||
the term is copied to the receiving thread and variable-bindings are
|
||||
thus lost. This call returns immediately.
|
||||
|
||||
If more than one thread is waiting for messages on the given queue and
|
||||
at least one of these is waiting with a partially instantiated
|
||||
@var{Term}, the waiting threads are \emph{all} sent a wakeup signal,
|
||||
@var{Term}, the waiting threads are @emph{all} sent a wakeup signal,
|
||||
starting a rush for the available messages in the queue. This behaviour
|
||||
can seriously harm performance with many threads waiting on the same
|
||||
queue as all-but-the-winner perform a useless scan of the queue. If
|
||||
there is only one waiting thread or all waiting threads wait with an
|
||||
unbound variable an arbitrary thread is restarted to scan the queue.%
|
||||
\footnote{See the documentation for the POSIX thread functions
|
||||
pthread_cond_signal() v.s.\ pthread_cond_broadcastt()
|
||||
for background information.}
|
||||
@comment \footnote{See the documentation for the POSIX thread functions
|
||||
@comment pthread_cond_signal() v.s.\ pthread_cond_broadcastt()
|
||||
@comment for background information.}
|
||||
|
||||
\predicate{thread_get_message}{1}{?Term}
|
||||
@item thread_get_message(?@var{Term})
|
||||
@findex thread_get_message/1
|
||||
@snindex thread_get_message/1
|
||||
@cnindex thread_get_message/1
|
||||
Examines the thread message-queue and if necessary blocks execution
|
||||
until a term that unifies to @var{Term} arrives in the queue. After
|
||||
a term from the queue has been unified unified to @var{Term}, the
|
||||
term is deleted from the queue and this predicate returns.
|
||||
|
||||
Please note that not-unifying messages remain in the queue. After
|
||||
the following has been executed, thread 1 has the term \term{b}{gnu}
|
||||
the following has been executed, thread 1 has the term @code{gnu}
|
||||
in its queue and continues execution using @var{A} is @code{gnat}.
|
||||
|
||||
\begin{code}
|
||||
@example
|
||||
<thread 1>
|
||||
thread_get_message(a(A)),
|
||||
|
||||
<thread 2>
|
||||
thread_send_message(b(gnu)),
|
||||
thread_send_message(a(gnat)),
|
||||
\end{code}
|
||||
@end example
|
||||
|
||||
See also thread_peek_message/1.
|
||||
See also @code{thread_peek_message/1}.
|
||||
|
||||
\predicate{thread_peek_message}{1}{?Term}
|
||||
@item thread_peek_message(?@var{Term})
|
||||
@findex thread_peek_message/1
|
||||
@snindex thread_peek_message/1
|
||||
@cnindex thread_peek_message/1
|
||||
Examines the thread message-queue and compares the queued terms
|
||||
with @var{Term} until one unifies or the end of the queue has been
|
||||
reached. In the first case the call succeeds (possibly instantiating
|
||||
@var{Term}. If no term from the queue unifies this call fails.
|
||||
|
||||
\predicate{message_queue_create}{1}{?Queue}
|
||||
@item thread_message_queue_create(?@var{Queue})
|
||||
@findex thread_message_queue_create/1
|
||||
@snindex thread_message_queue_create/1
|
||||
@cnindex thread_message_queue_create/1
|
||||
If @var{Queue} is an atom, create a named queue. To avoid ambiguity
|
||||
of thread_send_message/2, the name of a queue may not be in use as a
|
||||
thread-name. If @var{Queue} is unbound an anonymous queue is created
|
||||
and @var{Queue} is unified to its identifier.
|
||||
on @code{thread_send_message/2}, the name of a queue may not be in use
|
||||
as a thread-name. If @var{Queue} is unbound an anonymous queue is
|
||||
created and @var{Queue} is unified to its identifier.
|
||||
|
||||
\predicate{message_queue_destroy}{1}{+Queue}
|
||||
@item thread_message_queue_destroy(+@var{Queue})
|
||||
@findex thread_message_queue_destroy/1
|
||||
@snindex thread_message_queue_destroy/1
|
||||
@cnindex thread_message_queue_destroy/1
|
||||
Destroy a message queue created with message_queue_create/1. It is
|
||||
\emph{not} allows to destroy the queue of a thread. Neither is it
|
||||
@emph{not} allows to destroy the queue of a thread. Neither is it
|
||||
allowed to destroy a queue other threads are waiting for or, for
|
||||
anynymous message queues, may try to wait for later.%
|
||||
\bug{None of these constraints are properly enforced by the
|
||||
system in the current implementation. It is therefore
|
||||
advised not to delete queues unless you are absolutely
|
||||
sure it is safe.}
|
||||
|
||||
\predicate{thread_get_message}{2}{+Queue, ?Term}
|
||||
As thread_get_message/1, operating on a given queue. It is allowed (but
|
||||
not advised) to get messages from the queue of other threads.
|
||||
|
||||
\predicate{thread_get_message}{2}{+Queue, ?Term}
|
||||
@item thread_get_message(+@var{Queue}, +@var{Term})
|
||||
@findex thread_get_message/2
|
||||
@snindex thread_get_message/2
|
||||
@cnindex thread_get_message/2
|
||||
As thread_get_message/1, operating on a given queue. It is allowed to
|
||||
peek into another thread's message queue, an operation that can be used
|
||||
to check whether a thread has swallowed a message sent to it.
|
||||
@end table
|
||||
|
||||
|
||||
Explicit message queues are designed with the \jargon{worker-pool} model
|
||||
Explicit message queues are designed with the @emph{worker-pool} model
|
||||
in mind, where multiple threads wait on a single queue and pick up the
|
||||
first goal to execute. Below is a simple implementation where the
|
||||
workers execute arbitrary Prolog goals. Note that this example provides
|
||||
no means to tell when all work is done. This must be realised using
|
||||
additional synchronisation.
|
||||
|
||||
\begin{code}
|
||||
@example
|
||||
% create_workers(+Id, +N)
|
||||
%
|
||||
% Create a pool with given Id and number of workers.
|
||||
@ -12476,26 +12496,29 @@ do_work(Id) :-
|
||||
|
||||
work(Id, Goal) :-
|
||||
thread_send_message(Id, Goal).
|
||||
\end{code}
|
||||
@end example
|
||||
|
||||
|
||||
\subsection{Signalling threads}
|
||||
@node Signalling Threads, Threads and Dynamic Predicates,Message Queues, Thread Communication
|
||||
@subsection Signalling Threads
|
||||
|
||||
These predicates provide a mechanism to make another thread execute some
|
||||
goal as an \jargon{interrupt}. Signalling threads is safe as these
|
||||
goal as an @emph{interrupt}. Signalling threads is safe as these
|
||||
interrupts are only checked at safe points in the virtual machine.
|
||||
Nevertheless, signalling in multi-threaded environments should be
|
||||
handled with care as the receiving thread may hold a \jargon{mutex}
|
||||
handled with care as the receiving thread may hold a @emph{mutex}
|
||||
(see with_mutex). Signalling probably only makes sense to start
|
||||
debugging threads and to cancel no-longer-needed threads with throw/1,
|
||||
debugging threads and to cancel no-longer-needed threads with @code{throw/1},
|
||||
where the receiving thread should be designed carefully do handle
|
||||
exceptions at any point.
|
||||
|
||||
@table @code
|
||||
\predicate{thread_signal}{2}{+ThreadId, :Goal}
|
||||
@item thread_signal(+@var{ThreadId}, :@var{Goal})
|
||||
@findex thread_signal/2
|
||||
@snindex thread_signal/2
|
||||
@cnindex thread_signal/2
|
||||
Make thread @var{ThreadId} execute @var{Goal} at the first
|
||||
opportunity. In the current implementation, this implies at the first
|
||||
pass through the \jargon{Call-port}. The predicate thread_signal/2
|
||||
pass through the @emph{Call-port}. The predicate @code{thread_signal/2}
|
||||
itself places @var{Goal} into the signalled-thread's signal queue
|
||||
and returns immediately.
|
||||
|
||||
@ -12504,43 +12527,46 @@ multi-threading, mainly because the status of mutexes cannot be
|
||||
guaranteed easily. At the call-port, the Prolog virtual machine
|
||||
holds no locks and therefore the asynchronous execution is safe.
|
||||
|
||||
@var{Goal} can be any valid Prolog goal, including throw/1 to make
|
||||
the receiving thread generate an exception and trace/0 to start
|
||||
@var{Goal} can be any valid Prolog goal, including @code{throw/1} to make
|
||||
the receiving thread generate an exception and @code{trace/0} to start
|
||||
tracing the receiving thread.
|
||||
|
||||
In the Windows version, the receiving thread immediately executes
|
||||
the signal if it reaches a Windows GetMessage() call, which generally
|
||||
happens of the thread is waiting for (user-)input.
|
||||
@comment In the Windows version, the receiving thread immediately executes
|
||||
@comment the signal if it reaches a Windows GetMessage() call, which generally
|
||||
@comment happens of the thread is waiting for (user-)input.
|
||||
@end table
|
||||
|
||||
@node Threads and Dynamic Predicates, , Signalling Threads, Thread Communication
|
||||
@subsection Threads and Dynamic Predicates
|
||||
|
||||
\subsection{Threads and dynamic predicates} \label{sec:threadlocal}
|
||||
|
||||
Besides queues (\secref{msgqueue}) threads can share and exchange
|
||||
data using dynamic predicates. The multi-threaded version knows about
|
||||
two types of dynamic predicates. By default, a predicate declared
|
||||
\jargon{dynamic} (see dynamic/1) is shared by all threads. Each thread
|
||||
may assert, retract and run the dynamic predicate. Synchronisation
|
||||
inside Prolog guarantees the consistency of the predicate. Updates are
|
||||
\jargon{logical}: visible clauses are not affected by assert/retract
|
||||
Besides queues threads can share and exchange data using dynamic
|
||||
predicates. The multi-threaded version knows about two types of
|
||||
dynamic predicates. By default, a predicate declared @emph{dynamic}
|
||||
(see @code{dynamic/1}) is shared by all threads. Each thread may
|
||||
assert, retract and run the dynamic predicate. Synchronisation inside
|
||||
Prolog guarantees the consistency of the predicate. Updates are
|
||||
@emph{logical}: visible clauses are not affected by assert/retract
|
||||
after a query started on the predicate. In many cases primitive from
|
||||
\secref{threadsync} should be used to ensure application invariants on
|
||||
thread synchronysation should be used to ensure application invariants on
|
||||
the predicate are maintained.
|
||||
|
||||
Besides shared predicates, dynamic predicates can be declared with the
|
||||
thread_local/1 directive. Such predicates share their attributes, but
|
||||
the clause-list is different in each thread.
|
||||
@code{thread_local/1} directive. Such predicates share their
|
||||
attributes, but the clause-list is different in each thread.
|
||||
|
||||
@table @code
|
||||
\prefixop{thread_local}{+Functor/+Arity, \ldots}
|
||||
This directive is related to the dynamic/1 directive. It tells the
|
||||
system that the predicate may be modified using assert/1, retract/1,
|
||||
etc.\ during execution of the program. Unlike normal shared dynamic
|
||||
@item thread_local(@var{+Functor/Arity})
|
||||
@findex thread_local/1 (directive)
|
||||
@snindex thread_local/1 (directive)
|
||||
@cnindex thread_local/1 (directive)
|
||||
related to the dynamic/1 directive. It tells the system that the
|
||||
predicate may be modified using @code{assert/1}, @code{retract/1},
|
||||
etc, during execution of the program. Unlike normal shared dynamic
|
||||
data however each thread has its own clause-list for the predicate.
|
||||
As a thread starts, this clause list is empty. If there are still
|
||||
clauses as the thread terminates these are automatically reclaimed
|
||||
by the system (see also volatile/1). The thread_local property
|
||||
implies the properties dynamic and volatile.
|
||||
clauses as the thread terminates these are automatically reclaimed by
|
||||
the system. The thread_local property implies
|
||||
the property dynamic.
|
||||
|
||||
Thread-local dynamic predicates are intended for maintaining
|
||||
thread-specific state or intermediate results of a computation.
|
||||
@ -12550,34 +12576,31 @@ a file as in the example below as the clause is only visible from the
|
||||
thread that loaded the source-file. All other threads start with an
|
||||
empty clause-list.
|
||||
|
||||
\begin{code}
|
||||
@example
|
||||
:- thread_local
|
||||
foo/1.
|
||||
|
||||
foo(gnat).
|
||||
\end{code}
|
||||
@end example
|
||||
|
||||
\textbf{DISCLAIMER} Whether or not this declaration is apropriate in
|
||||
the sense of the proper mechanism to reach the goal is still debated.
|
||||
If you have strong feeling in favour or against, please share them
|
||||
in the SWI-Prolog mailing list.
|
||||
@end table
|
||||
|
||||
|
||||
\section{Thread synchronisation} \label{sec:threadsync}
|
||||
@node Thread Synchronisation, , Thread Communication, Threads
|
||||
@section Thread Synchronisation
|
||||
|
||||
All internal Prolog operations are thread-safe. This implies two Prolog
|
||||
threads can operate on the same dynamic predicate without corrupting the
|
||||
consistency of the predicate. This section deals with user-level
|
||||
\jargon{mutexes} (called \jargon{monitors} in ADA or
|
||||
\jargon{critical-sections} by Microsoft). A mutex is a
|
||||
{\bf MUT}ual {\bf EX}clusive device, which implies at most one thread
|
||||
can \jargon{hold} a mutex.
|
||||
@emph{mutexes} (called @emph{monitors} in ADA or
|
||||
@emph{critical-sections} by Microsoft). A mutex is a
|
||||
@emph{MUT}ual @emph{EX}clusive device, which implies at most one thread
|
||||
can @emph{hold} a mutex.
|
||||
|
||||
Mutexes are used to realise related updates to the Prolog database.
|
||||
With `related', we refer to the situation where a `transaction' implies
|
||||
two or more changes to the Prolog database. For example, we have a
|
||||
predicate address/2, representing the address of a person and we want
|
||||
predicate @code{address/2}, representing the address of a person and we want
|
||||
to change the address by retracting the old and asserting the new
|
||||
address. Between these two operations the database is invalid: this
|
||||
person has either no address or two addresses, depending on the
|
||||
@ -12585,7 +12608,7 @@ assert/retract order.
|
||||
|
||||
Here is how to realise a correct update:
|
||||
|
||||
\begin{code}
|
||||
@example
|
||||
:- initialization
|
||||
mutex_create(addressbook).
|
||||
|
||||
@ -12594,63 +12617,86 @@ change_address(Id, Address) :-
|
||||
retractall(address(Id, _)),
|
||||
asserta(address(Id, Address)),
|
||||
mutex_unlock(addressbook).
|
||||
\end{code}
|
||||
@end example
|
||||
|
||||
|
||||
@table @code
|
||||
\predicate{mutex_create}{1}{?MutexId}
|
||||
Create a mutex. if @var{MutexId} is an atom, a \jargon{named} mutex is
|
||||
@item mutex_create(?@var{MutexId})
|
||||
@findex mutex_create/1
|
||||
@snindex mutex_create/1
|
||||
@cnindex mutex_create/1
|
||||
Create a mutex. if @var{MutexId} is an atom, a @emph{named} mutex is
|
||||
created. If it is a variable, an anonymous mutex reference is returned.
|
||||
There is no limit to the number of mutexes that can be created.
|
||||
|
||||
\predicate{mutex_destroy}{1}{+MutexId}
|
||||
@item mutex_destroy(+@var{MutexId})
|
||||
@findex mutex_destroy/1
|
||||
@snindex mutex_destroy/1
|
||||
@cnindex mutex_destroy/1
|
||||
Destroy a mutex. After this call, @var{MutexId} becomes invalid and
|
||||
further references yield an \except{existence_error} exception.
|
||||
further references yield an @code{existence_error} exception.
|
||||
|
||||
\predicate{with_mutex}{2}{+MutexId, :Goal}
|
||||
@item with_mutex(+@var{MutexId}, :@var{Goal})
|
||||
@findex with_mutex/2
|
||||
@snindex with_mutex/2
|
||||
@cnindex with_mutex/2
|
||||
Execute @var{Goal} while holding @var{MutexId}. If @var{Goal} leaves
|
||||
choicepointes, these are destroyed (as in once/1). The mutex is unlocked
|
||||
choicepoints, these are destroyed (as in @code{once/1}). The mutex is unlocked
|
||||
regardless of whether @var{Goal} succeeds, fails or raises an exception.
|
||||
An exception thrown by @var{Goal} is re-thrown after the mutex has been
|
||||
successfully unlocked. See also mutex_create/2 and call_cleanup/3.
|
||||
successfully unlocked. See also @code{mutex_create/2}.
|
||||
|
||||
Although described in the thread-section, this predicate is also
|
||||
available in the single-threaded version, where it behaves simply as
|
||||
once/1.
|
||||
|
||||
\predicate{mutex_lock}{1}{+MutexId}
|
||||
Lock the mutex. Prolog mutexes are \jargon{recursive} mutexes: they
|
||||
@item mutex_lock(+@var{MutexId})
|
||||
@findex mutex_lock/1
|
||||
@snindex mutex_lock/1
|
||||
@cnindex mutex_lock/1
|
||||
Lock the mutex. Prolog mutexes are @emph{recursive} mutexes: they
|
||||
can be locked multiple times by the same thread. Only after unlocking
|
||||
it as many times as it is locked, the mutex becomes available for
|
||||
locking by other threads. If another thread has locked the mutex the
|
||||
calling thread is suspended until to mutex is unlocked.
|
||||
|
||||
If @var{MutexId} is an atom, and there is no current mutex with that
|
||||
name, the mutex is created automatically using mutex_create/1. This
|
||||
name, the mutex is created automatically using @code{mutex_create/1}. This
|
||||
implies named mutexes need not be declared explicitly.
|
||||
|
||||
Please note that locking and unlocking mutexes should be paired
|
||||
carefully. Especially make sure to unlock mutexes even if the protected
|
||||
code fails or raises an exception. For most common cases use
|
||||
with_mutex/2, wich provides a safer way for handling prolog-level
|
||||
mutexes. The predicate call_cleanup/[2-3] is another way to guarantee
|
||||
that the mutex is unlocked while retaining non-determinism.
|
||||
@code{with_mutex/2}, wich provides a safer way for handling prolog-level
|
||||
mutexes.
|
||||
|
||||
\predicate{mutex_trylock}{1}{+MutexId}
|
||||
@item mutex_trylock(+@var{MutexId})
|
||||
@findex mutex_trylock/1
|
||||
@snindex mutex_trylock/1
|
||||
@cnindex mutex_trylock/1
|
||||
As mutex_lock/1, but if the mutex is held by another thread, this
|
||||
predicates fails immediately.
|
||||
|
||||
\predicate{mutex_unlock}{1}{+MutexId}
|
||||
@item mutex_unlock(+@var{MutexId})
|
||||
@findex mutex_unlock/1
|
||||
@snindex mutex_unlock/1
|
||||
@cnindex mutex_unlock/1
|
||||
Unlock the mutex. This can only be called if the mutex is held by the
|
||||
calling thread. If this is not the case, a \except{permission_error}
|
||||
calling thread. If this is not the case, a @code{permission_error}
|
||||
exception is raised.
|
||||
|
||||
\predicate{mutex_unlock_all}{0}{}
|
||||
@item mutex_unlock_all
|
||||
@findex mutex_unlock_all/0
|
||||
@snindex mutex_unlock_all/0
|
||||
@cnindex mutex_unlock_all/0
|
||||
Unlock all mutexes held by the current thread. This call is especially
|
||||
useful to handle thread-termination using abort/0 or exceptions. See
|
||||
also thread_signal/2.
|
||||
useful to handle thread-termination using @code{abort/0} or exceptions. See
|
||||
also @code{thread_signal/2}.
|
||||
|
||||
\predicate{current_mutex}{3}{?MutexId, ?ThreadId, ?Count}
|
||||
@item current_mutex(?@var{MutexId}, ?@var{ThreadId}, ?@var{Count})
|
||||
@findex current_mutex/3
|
||||
@snindex current_mutex/3
|
||||
@cnindex current_mutex/3
|
||||
Enumerates all existing mutexes. If the mutex is held by some thread,
|
||||
@var{ThreadId} is unified with the identifier of te holding thread and
|
||||
@var{Count} with the recursive count of the mutex. Otherwise,
|
||||
@ -12658,8 +12704,7 @@ Enumerates all existing mutexes. If the mutex is held by some thread,
|
||||
@end table
|
||||
|
||||
|
||||
|
||||
@node Parallelism, Tabling, Logtalk, Extensions
|
||||
@node Parallelism, Tabling, Threads, Extensions
|
||||
@chapter Parallelism
|
||||
|
||||
@cindex parallelism
|
||||
|
Reference in New Issue
Block a user