SOURCE FILE: bubble.cpp



/*  Program Shell for:
    Parallel Bubble Sort   */

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

using namespace std;

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

      /* When debugging, we need to use this lock to get
         intelligible printouts of what the various threads are
         doing.  Warning:  Don't change how this is done.  If you
         insist on changing it, you need to have thought a WHOLE
         lot about the consequences. */

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




      /* This is the array that will be filled and then sorted by
         a group of child threads. */

int  cell[NUM_CELLS] ;

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

    /* 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 diagnostic output will
      probably seem excessive. */
int checking = 0 ;

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

/* ################################################## */
/*                         init                       */
/* ################################################## */
void init() 
{ 
      /* This code initializes special 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. */








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

}

/* ################################################## */
/*                        child                       */
/* ################################################## */
 void * child(void * idPtr) 
{
  int m_delay, j ;

       /* This is just a change of data type for convenience.
          Now 'me' is the number of the child.  Children have
          numbers from 1 to 31=NUM_CELLS-1. */
  int me = ((threadIdType *) (idPtr))->id, temp ;
  do
  {
       // Put entry code here.


    
        /* This next segment of code is 'critical' because TWO
           child threads can access most of the cells. */

    if (cell[me-1] > cell[me])    
    {
      temp = cell[me-1] ;
      cell[me-1] = cell[me] ;

       /* Delay code inserted here to magnify the chances that
          child threads will interfere with each other */
        m_delay = (int) random()%100 ;
        for (j=0; j<m_delay; j++) sched_yield();  

      cell[me] = temp ;
    }
         
         // Put exit code here.



  } while (true) ;

   pthread_exit ((void *)0) ;
}

/* ################################################## */
/*                       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 that contains an int
          field - it is a convenient data type to use as the
          parameter to the child function.  */
  threadIdType * idPtr ; 

  for (i = 1; i < NUM_CELLS ; i++) 
  {
         /* Allocate memory for another unit of memory of type
            threadIdType. */
    idPtr = new threadIdType ;

       /* 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.  The Mother
            forks the child and detaches with the next command,
            because she does not intend to "join" it -- to wait
            for it to exit and collect its exit status. */

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

  bool sorted ; 
  int m_delay, j;

     /* This code can be used to check to see if the list is
        sorted.  You can try to think of another way to do it, if
        you want.  It's possible for the child processes to
        figure out collectively whether the list is sorted. */

  do
  {
               /* You can insert random delays like the one below
                  where you want - to vary timing. */
    /* m_delay = (int) random()%100 ;
    for (j=0; j<m_delay; j++) sched_yield();  */

           /* MOTHER WALKS UP THE ARRAY, CHECKING */
    sorted = true ;

        // You may need to add some entry code here.

    for (i=1; i<NUM_CELLS; i++)
    {

        // You may need to add some entry code here.


      if (cell[i-1] > cell[i]) sorted = false ;

        // You may need to add some exit code here.

    }

        // You may need to add some exit code here.


  } while (!sorted) ;

       /* This code prints the array - which should be sorted
          now. */

  for (i=0; i<NUM_CELLS; i++) cout << cell[i] << endl ;
}

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

int main() 
{ 

     /* This calls the function that performs initializations. */
  init(); 
  int idx ;
         /* Read the (unsorted) input into the array */
  for (idx=0; idx<NUM_CELLS; idx++)  cin >> cell[idx] ;
         /* Echo the (unsorted) input to the screen. */
  for (idx=0; idx<NUM_CELLS; idx++)  cout << cell[idx] 
     << endl ;
  cout << endl ;

        /* Execute the mother() function, which creates the child
           threads that sort the list. */
  mother();
  return 0 ;
}