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:

@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);
    pari_thread_sync();
    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_valloc(struct pari_thread *pth, size_t s, size_t v, GEN arg) Allocate a PARI stack of size s which can grow to at most v (as with parisize and parisizemax) and associate it, together with the argument arg, with the PARI thread data pth.

void pari_thread_alloc(struct pari_thread *pth, size_t s, GEN arg) As above but the stack cannot grow beyond s.

void pari_thread_free(struct pari_thread *pth) Free the PARI stack attached to 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_sync(void) Record states from the main thread so that they are available to pari_thread_start(). Must be called in the main thread before the subthreads starts.

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}