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

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

This example is to show the basic functioning of syncQ, which can be
used to block until the sync variable has been written to.  Each value
written to the syncQ is read only once and the next pending read blocks
on the next value written to the syncQ.  The order of reads is not 
guaranteed.

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_SyncQ<int>& sync_boy;

public:
  MyThread(HPCxx_SyncQ<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_SyncQ<int> t_sync;

  int i,n;

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

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

  // Array of ints for the syncQ
  int m;

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

  // Get one value for each thread that is using the syncQ
  for(i=0;i<n;i++) {
  outLock.lock();
    cout << "enter a value for the syncQ: ";
    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);
}
