barrier.c

DownloadView Raw

/**
 * @file barrier.c
 *
 * Demonstrates how to build a barrier with condition variables.
 *
 * gcc -pthread barrier.c -o barrier
 */
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#define NUM_THREADS 25

pthread_mutex_t bar_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t bar_condition = PTHREAD_COND_INITIALIZER;
int bar_count;

void barrier(void)
{
    pthread_mutex_lock(&bar_mutex);
    bar_count++;
    if (bar_count == NUM_THREADS) {
        // This is the LAST thread to enter the barrier
 
        // Set bar_count to 0 so we can use the barrier again:
        bar_count = 0;

        // Tell all the sleeping threads to wake up!
        pthread_cond_broadcast(&bar_condition);
    } else {
        // Wait unlocks mutex and puts thread to sleep.
        // Put wait in while loop in case some other
        // event awakens thread.
        while (pthread_cond_wait(&bar_condition, &bar_mutex) != 0)
        {
            // Wait for a signal... if pthread_cond_wait returns a nonzero
            // status code then it may have been a spurious wakeup, so keep
            // waiting.
        }
        // Mutex is relocked at this point; we need to unlock it below.
    }
    pthread_mutex_unlock(&bar_mutex);
}

void *thread_procedure(void *arg)
{
    /* Each thread will sleep for a random amount of time and then print a
     * single dollar sign '$' character. Since we have a barrier below, all the
     * dollar signs will appear at roughly the same time. */
    int r = random() % 5;
    sleep(r);

    // ----------------- BARRIER ------------------ //
    //
    barrier();
    //
    // All threads MUST call barrier() before they
    // can proceed. Try commenting out the call to
    // barrier() to see how the program's output
    // changes.
    // -------------------------------------------- //

    printf("$");
    fflush(stdout);

    return NULL;
}

int main(void)
{
    printf("Starting threads...\n");

    pthread_t threads[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; ++i) {
        pthread_create(&threads[i], NULL, thread_procedure, NULL);
    }

    for (int i = 0; i < NUM_THREADS; ++i) {
        pthread_join(threads[i], NULL);
    }

    puts("");
    printf("Done!\n");
    printf("Now rerun the program without the call to barrier()...\n");

    return 0;
}