#include <hpcxx_rts.h>
#include <iostream.h>
#include <unistd.h>

/***********************************************************************
tjs - 98.09.21

This example is to show the basic functioning of threads, and does so
by having several threads spawned and running at one time.  sleep()
keeps them running at the same time.

***********************************************************************/

// MyThread inherited from HPCxx_Thread.
// MyThread::run() is the meat of the routine.  This is the code that
// will be run when MyThread::start() -- inherited from HPCxx_Thread
// -- is executed.

class MyThread : public HPCxx_Thread {
  char *x;
  int n;
  unsigned slept_time;

public:
  MyThread(char *y, int _n): x(y),n(_n),HPCxx_Thread(){}
  void run() {
    cout << "thread " << n << ":  thread id " << getThreadID() 
	 << " text passed in: " << x 
	 << " ...sleeping" << endl << flush;

    // NOTE, there is a member function sleep defined in the 
    // HPCxx-Thread class which sleeps for n milliseconds + m
    // microseconds.


    sleep(1000*(10-n),0);

    cout << "thread " << n << " awake, slept " << 10-n << endl << flush;

  }
};

int main(int argc, char **argv)
{
  // These two must come first
  HPCxx_Group *g;
  hpcxx_init(argc, argv, g);

  int i,n;

  cout << "how many threads do you want? " << flush;
  cin >> n;

  //Array of threads
  MyThread *t[n];

  cout << "from main(): spawning " << n << " threads" << endl << flush;

  // spawn the threads
  for(i=0;i<n;i++) {
    t[i] = new MyThread("Hello, world!",i);
    t[i]->start();
  }

  // Now the threads are running in parallel

  sleep(1);
  cout << endl << "from main(): " << n 
       << " threads spawned and running concurrently"
       << endl << flush;

  cout << endl << "from main(): now joining the threads" << endl << flush;

  cout << endl << "from main(): some group functions" << endl << flush;

  cout << "g->getNumContexts: " << g->getNumContexts() << endl << flush;
  cout << "g->getNumThreads: " << g->getNumThreads() << endl << flush;
  cout << "g->getName: " << g->getName() << endl << flush;

  cout << endl << "from main(): names of threads" << endl << flush;

  // names of the threads
  for(i=0;i<n;i++) {
    cout << t[i]->getName() << endl << flush;
  }

  cout << endl << "from main(): now joining the threads" << endl << flush;


  // join threads into single thread of execution
  for(i=0;i<n;i++) {
    t[i]->join();
  }

  // Now back to 1 thread

  cout << "from main(): DONE" << endl << flush;

  // clean up hpcxx.  This should be the last thing you do.
  return hpcxx_exit(g);
}
