/** * @file barrier.c * * Demonstrates how to build a barrier with condition variables. * * gcc -pthread barrier.c -o barrier */ #include #include #include #include #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; }