The barrier.c program demonstrates an implementation of a barrier for Solaris threads. (See "Parallelizing a Loop on a Shared-Memory Parallel Computer" for a definition of barriers.)
#define _REENTRANT /* Include Files */ #include <thread.h> #include <errno.h> /* Constants & Macros * /* Data Declarations */ typedef struct { int maxcnt; /* maximum number of runners */ struct _sb { cond_t wait_cv; /* cv for waiters at barrier */ mutex_t wait_lk; /* mutex for waiters at barrier */ int runners; /* number of running threads */ } sb[2]; struct _sb *sbp; /* current sub-barrier */ } barrier_t; /* * barrier_init - initialize a barrier variable. * */ int barrier_init( barrier_t *bp, int count, int type, void *arg ) { int n; int i; if (count < 1) return(EINVAL); bp->maxcnt = count; bp->sbp = &bp->sb[0]; for (i = 0; i < 2; ++i) { #if defined(__cplusplus) struct barrier_t::_sb *sbp = &( bp->sb[i] ); #else struct _sb *sbp = &( bp->sb[i] ); #endif sbp->runners = count; if (n = mutex_init(&sbp->wait_lk, type, arg)) return(n); if (n = cond_init(&sbp->wait_cv, type, arg)) return(n); } return(0); } /* * barrier_wait - wait at a barrier for everyone to arrive. * */ int barrier_wait(register barrier_t *bp) { #if defined(__cplusplus) register struct barrier_t::_sb *sbp = bp->sbp; #else register struct _sb *sbp = bp->sbp; #endif mutex_lock(&sbp->wait_lk); if (sbp->runners == 1) { /* last thread to reach barrier */ if (bp->maxcnt != 1) { /* reset runner count and switch sub-barriers */ sbp->runners = bp->maxcnt; bp->sbp = (bp->sbp == &bp->sb[0]) ? &bp->sb[1] : &bp->sb[0]; /* wake up the waiters */ cond_broadcast(&sbp->wait_cv); } } else { sbp->runners--; /* one less runner */ while (sbp->runners != bp->maxcnt) cond_wait( &sbp->wait_cv, &sbp->wait_lk); } mutex_unlock(&sbp->wait_lk); return(0); } /* * barrier_destroy - destroy a barrier variable. * */ int barrier_destroy(barrier_t *bp) { int n; int i; for (i=0; i < 2; ++ i) { if (n = cond_destroy(&bp->sb[i].wait_cv)) return( n ); if (n = mutex_destroy( &bp->sb[i].wait_lk)) return(n); } return(0); } #define NTHR 4 #define NCOMPUTATION 2 #define NITER 1000 #define NSQRT 1000 void * compute(barrier_t *ba ) { int count = NCOMPUTATION; while (count--) { barrier_wait( ba ); /* do parallel computation */ } } main( int argc, char *argv[] ) { int i; int niter; int nthr; barrier_t ba; double et; thread_t *tid; switch ( argc ) { default: case 3 : niter = atoi( argv[1] ); nthr = atoi( argv[2] ); break; case 2 : niter = atoi( argv[1] ); nthr = NTHR; break; case 1 : niter = NITER; nthr = NTHR; break; } barrier_init( &ba, nthr + 1, USYNC_THREAD, NULL ); tid = (thread_t *) calloc(nthr, sizeof(thread_t)); for (i = 0; i < nthr; ++i) { int n; if (n = thr_create(NULL, 0, (void *(*)( void *)) compute, &ba, NULL, &tid[i])) { errno = n; perror("thr_create"); exit(1); } } for (i = 0; i < NCOMPUTATION; i++) { barrier_wait(&ba ); /* do parallel algorithm */ } for (i = 0; i < nthr; i++) { thr_join(tid[i], NULL, NULL); } }