//
// Very simple program demonstrating the use of threads.
//
// Command-line argument is P (number of threads).
//
// Each thread creates a string containing "hello" message and writes
//   it to standard output.  No attempt is made to synchronize, but
//   by having each thread output its message in the form of a single
//   stream, we hope to avoid garbled output.  
//
#include <iostream>
#include <cstdlib>		// has exit(), etc.
#include <unistd.h>		// has usleep()
#include <pthread.h>		// has pthread_ routines
#include <string>
#include <strstream.h>		// has ostrstream class

// declaration for function to be executed by each thread
void * printHello(void * threadArg);

// ---- Main program -------------------------------------------------

int main(int argc, char* argv[]) {

  if (argc < 2) {
    cerr << "Usage:  " << argv[0] << " numThreads\n";
    exit(EXIT_FAILURE);
  }
  int P = atoi(argv[1]);

  // Set up IDs for threads (need a separate variable for each
  //   since they're shared among threads).
  int * threadIDs = new int[P];
  for (int i = 0; i < P; ++i)
    threadIDs[i] = i;

  // Start P new threads.
  pthread_t * threads = new pthread_t[P];
  for (int i = 0; i < P; ++i) 
    pthread_create(&threads[i], NULL, printHello, 
		   (void *) &threadIDs[i]);

  // Wait for all threads to complete.
  for (int i = 0; i < P; ++i) 
    pthread_join(threads[i], NULL);

  // Clean up and exit.
  delete [] threadIDs;
  delete [] threads;
  cout << "That's all, folks!\n";
  return EXIT_SUCCESS;
}

// ---- Code to be executed by each thread ---------------------------

// pre:  *threadArg is an integer "thread ID".
// post:  "hello" message printed to standard output.
//        return value is null pointer.
void * printHello(void * threadArg) {
  int * myID = (int *) threadArg;
  ostrstream messageStream;
  messageStream << "hello, world, ";
  // pointless pause, included to make the effects of 
  //   synchronization (or lack thereof) more obvious
  usleep(10);
  messageStream << "from thread " << *myID << endl;
  string message = messageStream.str();
  cout << message;
  pthread_exit((void *) NULL);
}