NPTL: The New Implementation of Threads for Linux

by L. Blunt Jackson





Listing One



#include <pthread.h>

#include <unistd.h>   /* for getpid() */

#include <stdio.h>

#include <malloc.h>



void* _obtain_thread_pid(void* arg)

{

    long *exit_status = malloc(sizeof(long));

    (void) arg; /* keep compiler quiet. */

    *exit_status = getpid();

    return exit_status;

}

int main()

{

    pthread_t thread;

    void *status_ptr;

    long *thread_pid;

    long process_pid = getpid();

    /* a well behaved application tests the return value of

    ** pthread_create to ensure there is no error. */

    pthread_create(&thread, NULL, &_obtain_thread_pid, NULL);

    pthread_join(thread, &status_ptr);

    thread_pid = (long*)status_ptr;

    if (*thread_pid != process_pid)

        printf("This is linked to the LinuxThreads library.\n");

    else

        printf("This is linked to the NPTL library.\n");

    return 0;

}





Listing Two



#include <pthread.h>

#include <sys/time.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#define __USE_POSIX

#include <limits.h>



static pthread_attr_t attr;

static void* _noop_thd(void* arg)

{

    (void) arg;

    return NULL;

}

static void* _thread_maker(void* arg)

{

    int to_produce = *(int*)arg;

    /* Sequentially create a number of threads that trivially exit. */

    while (to_produce) {

        pthread_t noop;

        pthread_create(&noop, &attr, &_noop_thd, NULL);

        pthread_join(noop, NULL);

        to_produce--;

    }

    return NULL;

}

int main(int argc, char **argv)

{

    struct timeval start;

    struct timeval fin;

    int top, sub;

    pthread_t *thread;

    pthread_attr_init(&attr);

    /* Minimize stack size per thread so that we can

    ** create more threads. */

    pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);

    /* Accept command line params.*/

    if (argc < 3) {

        printf("\nUSAGE: <#thread-producers> <#produced>\n\n");

        return 1;

    } else {

        top = atoi(argv[1]);

        sub = atoi(argv[2]);

        if (top < 1) top = 1;

        if (sub < 1) sub = 1;

        printf("Using %d parents and %d children for %d threads.\n",

                     top, sub, top * sub);

    }

    thread = calloc(top, sizeof(pthread_t));

    /* Start timer. */

    if (gettimeofday(&start, NULL)) {

        printf("Time of day failed.");

        abort();

    }

    for (int i = 0; i < top; i++)

        pthread_create(&thread[i], &attr, &_thread_maker, &sub);

    for (int i = 0; i < top; i++)

        pthread_join(thread[i], NULL);

    /* Stop timer. */

    if (gettimeofday(&fin, NULL)) {

        printf("Time of day failed at end.");

        abort();

    }

    /* Calculate the delta. */

    {

        int usec = fin.tv_usec - start.tv_usec;

        int sec  = fin.tv_sec  - start.tv_sec;

        if (usec < 0) {

            sec--;

            usec += 1000000;

        }

        printf("Time %d sec %d usec\n", sec, usec);

    }

    return 0;

}





Listing Three



#include <pthread.h>

#include <sys/time.h>

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <string.h>



#define __USE_POSIX

#include <limits.h>



static int crit_max;     /* number of critical regions.  */

static int iterations;   /* total per-thread iterations. */

static int thread_count; /* total number of threads.     */

static int start_count;  /* global protected by start_signal */

static pthread_cond_t   go;

static pthread_mutex_t  start_signal;

static pthread_mutex_t *critical_region;

static void _obtain_first_lock(int locknum)

{

    pthread_mutex_lock(&critical_region[locknum]);

    pthread_mutex_lock(&start_signal);

    start_count++;

    if (start_count == thread_count) {

        /* wait until all threads are here! */

        pthread_mutex_unlock(&start_signal);

        pthread_cond_broadcast(&go);

    } else {

        pthread_cond_wait(&go, &start_signal);

        pthread_mutex_unlock(&start_signal);

    }

}

static void* _contention_loop(void* arg)

{

    int curr, prev, iter;

    iter = 1;

    prev = curr = *(int*)arg;

    _obtain_first_lock(curr++);

    while (iter < iterations)

    {

       iter++;

        if (curr == crit_max) curr = 0;

        if (curr == prev) { /* don't block on our own lock! */

            curr++;

            continue;

        }

        pthread_mutex_lock(&critical_region[curr]);

        pthread_mutex_unlock(&critical_region[prev]);

        prev = curr;

        curr++;

    }

    pthread_mutex_unlock(&critical_region[prev]);

    return NULL;

}

static void _configure(int argc, char** argv)

{

    if (argc < 3) {

        printf("\nUSAGE: <threads> <per-thread-iterations>\n\n");

        abort();

    } else {

        thread_count = atoi(argv[1]);

        iterations   = atoi(argv[2]);

        if (thread_count < 1)  thread_count = 1;

        if (iterations   < 1)  iterations   = 1;

    }

    crit_max = thread_count + 1;

}

static void _prepare(pthread_attr_t *attr, pthread_t **thds)

{

    pthread_attr_init(attr);

    pthread_attr_setstacksize(attr, PTHREAD_STACK_MIN);

    critical_region = calloc(crit_max, sizeof(pthread_mutex_t));

    for (int i = 0; i < crit_max; i++)

        pthread_mutex_init(&critical_region[i], NULL);

    start_count = 0;

    pthread_cond_init(&go, NULL);

    pthread_mutex_init(&start_signal, NULL);

    *thds = calloc(thread_count, sizeof(pthread_t));

}

int main(int argc, char **argv)

{

    const int usec_per_sec = 1000000;

    long tot_usec;

    struct timeval start;

    struct timeval fin;

    pthread_t     *thread;

    pthread_attr_t attr;

    _configure(argc, argv);

    _prepare(&attr, &thread);

    gettimeofday(&start, NULL); /* start timer */

    for (int i = 0; i < thread_count; i++)

    {

        int *j = malloc(sizeof(int));

        *j = i;

        pthread_create(&thread[i], &attr, &_contention_loop, j);

    }

    for (int i = 0; i < thread_count; i++)

        pthread_join(thread[i], NULL);

    gettimeofday(&fin, NULL); /* stop timer */

    tot_usec = (fin.tv_sec  - start.tv_sec) * usec_per_sec;

    tot_usec += fin.tv_usec - start.tv_usec;

    printf("Total run time %.3f sec.\n", (double)tot_usec / usec_per_sec);

    return 0;

}











4



