SOURCE FILE: pyramid.cpp



/*  Cheer Leader Pyramid Program   */

#include <iostream>
#include <sched.h>
#include <time.h>
#include <pthread.h>
#include "sem.h"

#define PYR_COUNT 15

using namespace std;

extern sim_semaphore create_sim_sem(int) ;
extern void wait_sem (sim_semaphore) ;
extern void signal_sem (sim_semaphore) ;

      /* For technical reasons, we use the pthread mutex below,
         instead of a semaphore, to lock the screen for output.  Don't
         change this.  */

pthread_mutex_t stdoutLock ;

     /* Here declare whatever semaphores, flags, counters, and so
        forth, that you want to use for synchronization. Variables
        declared here will be visible to (shared by) all the threads
        in the task. */


   /* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */ 


     /* These are global variable to represent threads created
        dynamically. */
pthread_t thr[PYR_COUNT] ; 

    /* This is included to facilitate adding random delays in the code
       -- as a debugging aid. */
extern long random(void);  

   /* This can be changed to 1, but the resulting diagnostic output
      will probably seem excessive. */
int checking = 0 ;

     /* A data type - a struct (class) with an int field to represent
        a thread ID. */
struct threadIdType
{
  int id ;
};

/* ################################################## */
/*                         init                       */
/* ################################################## */
void init() 
{ 
      /* This code initializes special mutex lock for screen output.
         Just leave this alone. */
  if ( 0!=pthread_mutex_init(&stdoutLock, NULL) )
  {  cout << "MUTEX INITIALIZATION FAILURE!" << endl ;
     exit(-1) ;}

    /* Here insert the code you want to intialize semaphores, flags,
       counters, and so forth. */



   /* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */ 



       /* This initializes a random number generator */ 
  srandom(time((time_t *) 0));
}

/* ################################################## */
/*                     rand_delay                     */
/* ################################################## */
void rand_delay(int max) 
{
  int m_delay, j ;
  m_delay = (int) random()%max ;
  for (j=0; j<m_delay; j++) sched_yield();  
}

/* ################################################## */
/*                childMessage                        */
/* ################################################## */
void childMessage (int ID)
{
   pthread_mutex_lock(&stdoutLock) ;
   cout << "\nCHEER LEADER # " << ID 
        << " is now in position.\n" ;
   pthread_mutex_unlock(&stdoutLock) ;
}

/* ################################################## */
/*                        child                       */
/* ################################################## */

 void * child(void * idPtr) 
{
       /* This is just a change of data type for convenience.  Now
          'me' is the number of the child.  Children have numbers from
          0 to 14. */
  int me = ((threadIdType *) (idPtr))->id, temp ;

       /* Delay code inserted here to magnify the chances that child
          threads will interfere with each other.  The student
          completing the program should think of more places in the
          code where inserting random delays are likely to 'stress
          test' the program, and put more calls to rand_delay there.
          Better still, arrange for one half of the pyramid to get
          much higher average delays than the other half, by calling
          rand_delay with different values for the max delay parameter
          (100 is used in the call just below.) */
  rand_delay(100) ;

       /* You need to put some of the synchronization code before the
          statement below, wher the child process declares it has
          joined the pyramid. */



   /* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */ 



  childMessage(me) ;  // get into position
  
      /* Depending on what amount of synchronization code you placed
         earlier in this function, you may need some more here, before
         the child exits (and 'dies'). */



   /* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */ 



}

/* ################################################## */
/*                       mother                       */
/* ################################################## */

/* The mother spawns a given number of children and then waits for
   them all to finish.  */

void mother() 
{ 
  int i; 

       /* This is a pointer to a struct (class) that contains an int
          field - it is a convenient data type to use as the parameter
          to the child function.  */
  threadIdType * idPtr ; 

  for (i = 0; i < PYR_COUNT ; i++) 
  {

        /* Mother forks a child and detaches it 
           - she will not join it. */
    idPtr = new threadIdType ; // allocating memory for struct

       /* This records the current index as this child's ID */
    idPtr->id = i ; 

         /* The call below is what actually creates the child thread
            and passes a pointer to the struct 'idPtr' as the
            parameter to the child function. */

    if ( 0!=pthread_create(&thr[i], NULL, child, (void *) idPtr) )
    {  pthread_mutex_lock(&stdoutLock) ;
       cout << "THREAD CREATION FAILURE!" << endl ;
       pthread_mutex_unlock(&stdoutLock) ;
       exit(-1) ; }
     
    if (0!=pthread_detach(thr[i]))
    {  pthread_mutex_lock(&stdoutLock) ;
       cout << "THREAD DETACHMENT FAILURE!" << endl ;
       pthread_mutex_unlock(&stdoutLock) ;
       exit(-1) ;}
  }

  pthread_mutex_lock(&stdoutLock) ;
  cout << "\n\n Mother Finishes Spawning Threads.\n\n"   << endl ;
  pthread_mutex_unlock(&stdoutLock) ;

    /* Some code is needed here to make the mother thread delay until
       all the child threads have finished executing. */


   /* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */ 


  pthread_mutex_lock(&stdoutLock) ;
  cout << "\n\nAll children are now in position.\n" ;
  cout << "Mother exiting ... \n\n" ;
  pthread_mutex_unlock(&stdoutLock) ;

}

/* ################################################## */
/*                         main                       */
/* ################################################## */

int main() 
{ 

     /* This calls the function that performs initializations. */
  init(); 

        /* Execute the mother() function */ 
  mother();

  return 0 ;
}