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

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

This example is to show the basic functioning of mutex, and does so
by having several threads block on a mutex.

Note that the lock is also used to guard writes to stdout.

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

// 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.

HPCxx_Mutex mutex;  // note that scope is this file

class MyThread : public HPCxx_Thread {
  int n;

public:
  MyThread(char *y, int _n): n(_n),HPCxx_Thread(){}

  // set mutex lock, sleep, release lock

  void run() {

    mutex.lock();

    cout << "thread " << n << ":  thread id " << getThreadID() 
	 << " ...sleeping" << endl << flush;

    mutex.unlock();

    // this sleep alters the order in which threads will get the lock

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

    mutex.lock();

    cout << "thread " << n << " has the lock" << endl << flush;
    sleep(500,0);

    mutex.unlock();
  }
};

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

  mutex.lock();

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

  mutex.unlock();

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