#include <pthread.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <atomic.h> static pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; static pthread_mutex_t mut1 = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER; static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; static bool last_round; static int ntogo; static bool alldone; static void * cons (void *arg) { pthread_mutex_lock (&mut1); do { if (atomic_decrement_and_test (&ntogo)) { pthread_mutex_lock (&mut2); alldone = true; pthread_cond_signal (&cond2); pthread_mutex_unlock (&mut2); } pthread_cond_wait (&cond1, &mut1); } while (! last_round); pthread_mutex_unlock (&mut1); return NULL; } int main (int argc, char *argv[]) { int opt; int err; int nthreads = 10; int nrounds = 100; bool keeplock = false; while ((opt = getopt (argc, argv, "n:r:k")) != -1) switch (opt) { case 'n': nthreads = atol (optarg); break; case 'r': nrounds = atol (optarg); break; case 'k': keeplock = true; break; } ntogo = nthreads; pthread_t th[nthreads]; int i; for (i = 0; __builtin_expect (i < nthreads, 1); ++i) if (__builtin_expect ((err = pthread_create (&th[i], NULL, cons, (void *) (long) i)) != 0, 0)) printf ("pthread_create: %s\n", strerror (err)); for (i = 0; __builtin_expect (i < nrounds, 1); ++i) { pthread_mutex_lock (&mut2); while (! alldone) pthread_cond_wait (&cond2, &mut2); pthread_mutex_unlock (&mut2); pthread_mutex_lock (&mut1); if (! keeplock) pthread_mutex_unlock (&mut1); ntogo = nthreads; alldone = false; if (i + 1 >= nrounds) last_round = true; pthread_cond_broadcast (&cond1); if (keeplock) pthread_mutex_unlock (&mut1); } for (i = 0; i < nthreads; ++i) if ((err = pthread_join (th[i], NULL)) != 0) printf ("pthread_create: %s\n", strerror (err)); return 0; }