Appendix B
Solaris Threads Example: barrier.c
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.)
Example B-1 Solaris Threads Example: barrier.c
#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);
}
}
|