barrier.c プログラムは、Solaris スレッドのためのバリアの実装例です。(バリアの定義については、「共有メモリー型の並列コンピュータでのループの並列化」を参照してください。)
#define _REENTRANT /* インクルードファイル */ #include <thread.h> #include <errno.h> /* 定数とマクロ */ /* データ宣言 */ typedef struct { int maxcnt; /* スレッドの最大数 */ struct _sb { cond_t wait_cv; /* バリアで待つスレッドの cv */ mutex_t wait_lk; /* バリアで待つスレッドの mutex */ int runners; /* 実行するスレッド数 */ } sb[2]; struct _sb *sbp; /* 現在のサブバリア */ } barrier_t; /* * barrier_init - バリア変数を初期化する */ 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 - 全部が到着するまでバリアで待つ */ 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) { /* バリアに最後に到着したスレッド */ if (bp->maxcnt != 1) { /* 実行スレッドカウントをリセットし、サブバリアを切り替える */ sbp->runners = bp->maxcnt; bp->sbp = (bp->sbp == &bp->sb[0]) ? &bp->sb[1] : &bp->sb[0]; /* 待ちスレッドを呼び起こす */ cond_broadcast(&sbp->wait_cv); } } else { sbp->runners--; /* 1 小さい実行スレッド */ while (sbp->runners != bp->maxcnt) cond_wait( &sbp->wait_cv, &sbp->wait_lk); } mutex_unlock(&sbp->wait_lk); return(0); } /* * barrier_destroy - バリア変数を削除する */ 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 ); /* 並列計算 */ } } 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 ); /* 並列アルゴリズム */ } for (i = 0; i < nthr; i++) { thr_join(tid[i], NULL, NULL); } }