NAME

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:

Child 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;
  }

Parent 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.

Under this model, some PARI states are reset in new threads. In particular

* the random number generator is reset to the starting seed;

* the system stack exhaustion checking code, meant to catch infinite recursions, is disabled (use pari_stackcheck_init() to reenable it);

* cached real constants (returned by mppi, mpeuler and mplog2) are not shared between threads and will be recomputed as needed;

* error handlers (set with trap()) are reset.

The following sample program can be compiled using

      cc thread.c -o thread.o -lpari -lpthread

(Add -I/-L paths as necessary.)

file{../examples/thread.c}