All foreign code linked to the multithreading 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 multithreaded C and Prolog applications you should first familiarise yourself with writing multithreaded applications in C (C++).
If you are using SWI-Prolog as an embedded engine in a multithreaded
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 10.6.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 it when finished, as opposed to the model from section 10.6.2, where threads temporarily use a Prolog engine.
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 10.6.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.202The
structure layout changed in version 7.7.14. 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. The flags
field defines the following flags:
typedef struct { size_t stack_limit; /* Total stack limit (bytes) */ size_t table_space; /* Total tabling space limit (bytes) */ char * alias; /* alias name */ int (*cancel)(int thread); /* cancel function */ intptr_t flags; /* PL_THREAD_* flags */ size_t max_queue_size; /* Max size of associated queue */ } 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 multithreading, -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.