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:
vsc 2004-03-08 15:38:36 +00:00
parent cd3142c211
commit dbe36978b6
1 changed files with 168 additions and 123 deletions

View File

@ -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