threads/pthread_barrier_demo.c

This is threads/pthread_barrier_demo.c, an example to accompany the book, The Linux Programming Interface.

This file is not printed in the book; it is a supplementary file for Chapter 30.

The source code file is copyright 2024, Michael Kerrisk, and is licensed under the GNU General Public License, version 3.

In the listing below, the names of Linux system calls and C library functions are hyperlinked to manual pages from the Linux man-pages project, and the names of functions implemented in the book are hyperlinked to the implementations of those functions.

 

Download threads/pthread_barrier_demo.c

  Cover of The Linux Programming Interface

Function list (Bold in this list means a function is not static)

/* pthread_barrier_demo.c

   A demonstration of the use of the pthreads barrier API.

   Usage: pthread_barrier_demo num-barriers num-threads

   The program creates 'num-threads' threads, each of which loop
   'num-threads' times, waiting on the same barrier.
*/
#include <pthread.h>
#include "tlpi_hdr.h"

static pthread_barrier_t barrier;
                                /* Barrier waited on by all threads */

static int numBarriers;         /* Number of times the threads will
                                   pass the barrier */
static void *
threadFunc(void *arg)
{
    long threadNum = (long) arg;

    printf("Thread %ld started\n", threadNum);

    /* Seed the random number generator based on the current time
       (so that we get different seeds on each run) plus thread
       number (so that each thread gets a unique seed). */

    srandom(time(NULL) + threadNum);

    /* Each thread loops, sleeping for a few seconds and then waiting
       on the barrier. The loop terminates when each thread has passed
       the barrier 'numBarriers' times. */

    for (int j = 0; j < numBarriers; j++) {

        int nsecs = random() % 5 + 1;   /* Sleep for 1 to 5 seconds */
        sleep(nsecs);

        /* Calling pthread_barrier_wait() causes each thread to block
           until the call has been made by number of threads specified
           in the pthread_barrier_init() call. */

        printf("Thread %ld about to wait on barrier %d "
                "after sleeping %d seconds\n", threadNum, j, nsecs);
        int s = pthread_barrier_wait(&barrier);

        /* After the required number of threads have called
           pthread_barrier_wait(), all of the threads unblock, and
           the barrier is reset to the state it had after the call to
           pthread_barrier_init(). In other words, the barrier can be
           once again used by the threads as a synchronization point.

           On success, pthread_barrier_wait() returns the special value
           PTHREAD_BARRIER_SERIAL_THREAD in exactly one of the waiting
           threads, and 0 in all of the other threads. This permits
           the program to ensure that some action is performed exactly
           once each time a barrier is passed. */

        if (s == 0) {
            printf("Thread %ld passed barrier %d: return value was 0\n",
                    threadNum, j);

        } else if (s == PTHREAD_BARRIER_SERIAL_THREAD) {
            printf("Thread %ld passed barrier %d: return value was "
                    "PTHREAD_BARRIER_SERIAL_THREAD\n", threadNum, j);

            /* In the thread that gets the PTHREAD_BARRIER_SERIAL_THREAD
               return value, we briefly delay, and then print a newline
               character. This should give all of the threads a chance
               to print the message saying they have passed the barrier,
               and then provide a newline that separates those messages
               from subsequent output. (The only purpose of this step
               is to make the program output a little easier to read.) */

            usleep(100000);
            printf("\n");

        } else {        /* Error */
            errExitEN(s, "pthread_barrier_wait (%ld)", threadNum);
        }
    }

    /* Print out thread termination message after a briefly delaying,
       so that the other threads have a chance to display the return
       value they received from pthread_barrier_wait(). (This simply
       makes the program output a little easier to read.)*/

    usleep(200000);
    printf("Thread %ld terminating\n", threadNum);

    return NULL;
}
int
main(int argc, char *argv[])
{
    if (argc != 3 || strcmp(argv[1], "--help") == 0)
        usageErr("%s num-barriers num-threads\n", argv[0]);

    numBarriers = atoi(argv[1]);
    int numThreads = atoi(argv[2]);

    /* Allocate array to hold thread IDs */

    pthread_t *tid = calloc(numThreads, sizeof(pthread_t));
    if (tid == NULL)
        errExit("calloc");

    /* Initialize the barrier. The final argument specifies the
       number of threads that must call pthread_barrier_wait()
       before any thread will unblock from that call. */

    int s = pthread_barrier_init(&barrier, NULL, numThreads);
    if (s != 0)
        errExitEN(s, "pthread_barrier_init");

    /* Create 'numThreads' threads */

    for (long threadNum = 0; threadNum < numThreads; threadNum++) {
        s = pthread_create(&tid[threadNum], NULL, threadFunc,
                (void *) threadNum);
        if (s != 0)
            errExitEN(s, "pthread_create");
    }

    /* Each thread prints a start-up message. We briefly delay,
       and then print a newline character so that an empty line
       appears after the start-up messages. */

    usleep(100000);
    printf("\n");

    /* Wait for all of the threads to terminate */

    for (int threadNum = 0; threadNum < numThreads; threadNum++) {
        s = pthread_join(tid[threadNum], NULL);
        if (s != 0)
            errExitEN(s, "pthread_join");
    }

    exit(EXIT_SUCCESS);
}

 

Download threads/pthread_barrier_demo.c

Note that, in most cases, the programs rendered in these web pages are not free standing: you'll typically also need a few other source files (mostly in the lib/ subdirectory) as well. Generally, it's easier to just download the entire source tarball and build the programs with make(1). By hovering your mouse over the various hyperlinked include files and function calls above, you can see which other source files this file depends on.

Valid XHTML 1.1