多线程编程指南

附录 B Solaris 线程示例: barrier.c

barrier.c 程序演示了 Solaris 线程的屏障实现。有关屏障的定义,请参见在共享内存并行计算机上并行化循环


示例 B–1 Solaris 线程示例: 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);

	}

		

}