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);
}
}
|