All foreign-code linked to the multi-threading version of SWI-Prolog should be thread-safe (reentrant) or guarded in Prolog using with_mutex/2 from simultaneous access from multiple Prolog threads. If you want to write mixed multi-threaded C and Prolog application you should first familiarise yourself with writing multi-threaded applications in C (C++).
If you are using SWI-Prolog as an embedded engine in a multi-threaded
application you can access the Prolog engine from multiple threads by
creating an engine in each thread from which you call Prolog.
Without creating an engine, a thread can only use functions that do
not use the term_t
type (for example
PL_new_atom()).
The system supports two models. Section 8.7.1 describes the original one-to-one mapping. In this schema a native thread attaches a Prolog thread if it needs to call Prolog and detaches is when finished, as opposed to the model from section 8.7.2 where threads temporary use a Prolog engine.
Please note that the interface below will only work if threading in your application is based on the same thread-library as used to compile SWI-Prolog.
In the one-to-one model, the thread that called PL_initialise() has a Prolog engine attached. If another C-thread in the system wishes to call Prolog it must first attach an engine using PL_thread_attach_engine() and call PL_thread_destroy_engine() after all Prolog work is finished. This model is especially suitable with long running threads that need to do Prolog work regularly. See section 8.7.2 for the alternative many-to-many model.
NULL
to create a thread
with default attributes. Otherwise it is a pointer to a structure with
the definition below. For any field with value `0', the default is used.
The cancel
field may be filled with a pointer to a function
that is called when PL_cleanup() terminates the running Prolog engines.
If this function is not present or returns FALSE
pthread_cancel() is used.
typedef struct { unsigned long local_size; /* Stack sizes (K-bytes) */ unsigned long global_size; unsigned long trail_size; unsigned long argument_size; char * alias; /* alias name */ int (*cancel)(int thread); } PL_thread_attr_t;
The structure may be destroyed after PL_thread_attach_engine() has returned. On success it returns the Prolog identifier for the thread (as returned by PL_thread_self()). If an error occurs, -1 is returned. If this Prolog is not compiled for multi-threading, -2 is returned.
TRUE
on
success and FALSE
if the calling thread has no engine or
this Prolog does not support threads.
Please note that construction and destruction of engines are relatively expensive operations. Only destroy an engine if performance is not critical and memory is a critical resource.
void *
argument holding
closure. If global is TRUE
, the
handler is installed
for all threads. Globally installed handlers are executed after
the thread-local handlers. If the handler is installed local for the
current thread only (global == FALSE
) it is
stored in the same FIFO queue as used by thread_at_exit/1.
In this model Prolog engines live as entities that are independent from threads. If a thread needs to call Prolog it takes one of the engines from the pool and returns the engine when done. This model is suitable in the following identified cases:
In the single-threaded version this call always returns NULL
,
indicating failure.
TRUE
, on failure the
return value is FALSE
.NULL
the current engine associated with the calling
thread is stored at the given location. If engine equals
PL_ENGINE_MAIN
the initial engine is attached to the
calling thread. If engine is PL_ENGINE_CURRENT
the engine is not changed. This can be used to query the current engine.
This call returns
PL_ENGINE_SET
if the engine was switched successfully,
PL_ENGINE_INVAL
if engine is not a valid engine
handle and
PL_ENGINE_INUSE
if the engine is currently in use by
another thread.
Engines can be changed at any time. For example, it is allowed to
select an engine to initiate a Prolog goal, detach it and at a later
moment execute the goal from another thread. Note however that the
term_t
, qid_t
and fid_t
types are
interpreted relative to the engine for which they are created. Behaviour
when passing one of these types from one engine to another is undefined.
In the single-threaded version this call only succeeds if engine refers to the main engine.
In theory it is possible to port the API of section 8.7.2 to the single-threaded version of SWI-Prolog. This allows C-programs to control multiple Prolog engines concurrently. This has not yet been realised.