Appendix - PARI and threads
To use PARI in multi-threaded programs, you must configure it using
Configure --enable-tls
. Your system must implement the __thread
storage class. As a major side effect, this breaks the libpari
ABI: the
resulting library is not compatible with the old one, and -tls
is
appended to the PARI library soname
. On the other hand, this library is
now thread-safe.
PARI provides some functions to set up PARI subthreads. In our model, each concurrent thread needs its own PARI stack. The following scheme is used:
@3Child thread:
void *child_thread(void *arg) { GEN data = pari_thread_start((struct pari_thread*)arg); GEN result = ...; /* Compute result from data */ pari_thread_close(); return (void*)result; }
@3Parent thread:
pthread_t th; struct pari_thread pth; GEN data, result;
pari_thread_alloc(&pth, s, data); pthread_create(&th, NULL, &child_thread, (void*)&pth); /* start child */ ... /* do stuff in parent */ pthread_join(th, (void*)&result); /* wait until child terminates */ result = gcopy(result); /* copy result from thread stack to main stack */ pari_thread_free(&pth); /* ... and clean up */
void
pari_thread_alloc(struct pari_thread *pth, size_t s, GEN arg)
Allocate a PARI stack of size s
and associate it, together with the
argument arg
, with the PARI thread data pth
.
void
pari_thread_free(struct pari_thread *pth)
Free the PARI stack associated with the PARI thread data pth
. This
is called after the child thread terminates, i.e. after
pthread_join
in the parent. Any GEN
objects returned by the
child in the thread stack need to be saved before running this command.
void
pari_thread_init(void)
Initialize the thread-local PARI data structures. This function is called by
pari_thread_start
.
GEN
pari_thread_start(struct pari_thread *t)
Initialize the thread-local PARI data structures and set up the thread stack
using the PARI thread data pth
. This function returns the thread
argument arg
that was given to pari_thread_alloc
.
void
pari_thread_close(void)
Free the thread-local PARI data structures, but keeping the thread stack, so
that a GEN
returned by the thread remains valid.
@3Under this model, some PARI states are reset in new threads. In particular
@3* the random number generator is reset to the starting seed;
@3* the system stack exhaustion checking code, meant to catch infinite
recursions, is disabled (use pari_stackcheck_init()
to reenable it);
@3* cached real constants (returned by mppi
, mpeuler
and
mplog2
) are not shared between threads and will be recomputed as
needed;
@3The following sample program can be compiled using
cc thread.c -o thread.o -lpari -lpthread
(Add -I/-L
paths as necessary.)
@3file{../examples/thread.c}