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

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

This example is to show the basic functioning of sync, which can be
used to block until the sync variable has been written to.  Once
the value has been written to, those reading it read it as a const.

If a read is attempted before it is written to, the reader blocks.

Note: mutex used to protect cout sections

***********************************************************************/
HPCxx_Mutex outLock;  // note that scope is this file

// 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 {
  int myID;
  HPCxx_Sync<int>& sync_boy;

public:
  MyThread(HPCxx_Sync<int>& _sync_boy, int _myID): sync_boy(_sync_boy), 
    myID(_myID),HPCxx_Thread(){}

  // read sync, which will cause block until its value is changed.
  // in this case, main() changes the value.

  void run() {
    int sync_value;

    outLock.lock();
    cout << "thread " << myID << " blocking on read of sync_value" 
	 << endl << flush;
    outLock.unlock();

    sync_boy.read(sync_value);

    outLock.lock();
    cout << "thread " << myID << " read sync_value " << sync_value
	 << endl << flush;
    outLock.unlock();
  }
};

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

  HPCxx_Sync<int> t_sync;

  int i,n,m;

  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(t_sync,i);
    t[i]->start();
  }

  sleep(2);
  outLock.lock();
  cout << "enter an integer to sync the threads: ";
  cin >> m;
  outLock.unlock();
  
  t_sync=m;

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

  // Now back to 1 thread

  outLock.lock();
  cout << "from main(): DONE" << endl << flush;
  outLock.unlock();

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