Example : Barrier.C

Classes/Techniques Demonstrated :

Barrier.C

The most basic group synchonization operation is the barrier. A group of threads can synchronize at a point in code by calling a barrier, which forces them to halt until the rest of the threads in the group have also called the barrier. This is accomplished in the following steps:

We first allocate an object of type HPCxx_Group and set the number of threads to the maximum number that will participate in the operation. For example, to set the thread count on the main group to be 13 we can write the following.

      HPCxx_Group *g;
      g->setThreadCout(13);
      HPCxx_Barrier barrier(g);
      
As shown above, a HPCxx_Barrier object must be allocated for the group. This can be accomplished in three ways:

The constructor for the barrier takes a reference to the Group object.

Each thread that will participate in the barrier operation must then acquire a key from the barrier object with the getKey() function. (Threads do not have a natural integer index, so the key serves to enumerate threades associated with a group. While order is not essential for the operation of a barrier, it is important for reductions and scan operations.)

This example demonstrates the use of a barier to synchronize a number of threads which are all working to fill in a unique section of an array, the address of which they all share. Once every thread has filled in its section then each thread can independantly verify the sum of the values in the array, which will prove (beyond something heretically flukey) that they do each have the same array.

class MyThread : public HPCxx_Thread {
  HPCxx_Barrier &barrier;
  int *infoAr;
  int totalThreads, myId, count, myKey;
  
public:
  MyThread(int n, int id, int *ar, HPCxx_Barrier &_barrier):
    totalThreads(n), myId(id), infoAr(ar), barrier(_barrier), HPCxx_Thread(){}
  void run() {
    int total=0;
    
    myKey=barrier.getKey();
    cout << "Thread " << myId << " generating array values..." << endl;

    for(count=10*myId; count<10*(myId+1); count++) {
      infoAr[count]=(int)(1000*drand48());
    }
    
    cout << "Thread " << myId << " finished and entering barrier..." << endl;

    barrier(myKey);

    for(count=0; count<10*totalThreads; count++) {
      total+=infoAr[count];
    }

    cout << "Thread  " << myId << " computed sum : " << total << endl;
    
  } 
};

int foo(int n, HPCxx_Barrier barrier){
  MyThread *t[100];
  int *infoAr = new int[n*10];
  int total=0, count=0, key0;

  key0=barrier.getKey();
  for(int i = 0; i < n; i++){
    t[i] = new MyThread(n, i, infoAr, barrier);
    t[i]->start();
  }

  barrier(key0);

  for(count=0; count < n*10; count++) {
    cout << "Array value " << count << " is " <<  infoAr[count] << endl << flush;
  }
  cout << "DONE" << endl << flush;
  return 0;
}


int main(int argc, char **argv)
{
  HPCxx_Group *g;
  int n;

  hpcxx_init(argc, argv, g);

  cout << "Number of threads : " << endl << flush;
  cin >> n;
  g->setNumThreads(n+1);
  HPCxx_Barrier barrier(*g);

  foo(n, barrier);
  return hpcxx_exit(g);
}
  

hpc++@extreme.indiana.edu

Last modified: Thu Apr 22 02:12:38 EST 1999