So far we have assumed that the goal called in thread_create/2 terminates normally -- by success or failure. But what if a thread throws an error while executing a goal? How long should error information for a thread persist, and how can it be checked?
Our approach relies on the semantics of Pthreads, which can be either
joinable or detached. Within this framework, we consider
a thread to be valid if it has not yet terminated, or if it is
joinable and has not yet been joined. After a joinable Pthread
has terminated, status information about
persists until some other thread joins it -- at which time the
information is removed. On the other hand, if
is detached,
status information is removed as soon as
terminates.
Reclamation of thread status information may be contrasted to that of
thread-specific data structures such as stacks. Upon normal or
exceptional termination of
, any memory automatically
allocated in the process of initializing
's, or executing
its goal - including stacks, private dynamic code, private tables is
reclaimed. In addition, any mutexes held by
, are released.
On the other hand, XSB-specific status information about threads
follows the Pthread model: by default, error information is available
when joining a joinable thread, but not otherwise 7.3.
?- thread_create(functor(X,Y,Z),F).is executed. By default, this will produce the result
X = _h113 Y = _h127 Z = _h141 F = 1++Error[XSB/Runtime/P]: [Instantiation] in arg 2 of predicate functor/3In fact, the variable bindings are output to STDOUT, while the error message
++Error[XSB/Runtime/P]: [Instantiation] in arg 2 of predicate functor/3is output to STDERR, and may be redirected. The call
?- thread_join(2,Error).returns
Error = exception(error(instantiation_error, in arg 2 of predicate functor/3,
[[Forward Continuation...,... standard:call/1,... standard:catch/3],
Backward Continuation...]))
In other words, Error is instantiated to a exception/1
structure, containing a standard XSB error term (including backtrace).As with pthreads, XSB threads are created as joinable by default, but can be created as detached using an option in thread_create/3. Alternatively, a thread created as joinable can be made detached by thread_detach/1. All of the predicates mentioned in this section are fully described in Section 7.7.