Dining Philosophers: C Example

Andréa M. Matsunaga & Maurício O. Tsugawa
(Copy from The Brazos Web Site)

 

/* DiningPhilosophers.c */

#include "windows.h"
#include "brazosinc.h"
#include <stdlib.h>
#include <time.h>
#include <stdio.h>

/* Global data declarations */

#define NUM_PHILOSOPHERS 64  
/* maximum number of philosophers */

int NP;                                                      /* number of philosophers for this run- same as TOTAL_USER_THREADS */

USHORT mutex= (USHORT) 2;

int* freeForks;
                                       /* shared data structure - must be allocated with G_MALLOC
                                                                      freeForks[i] is how many forks are available to philosopher i */


int* mealsEaten;
                                   /* shared data structure - must be allocated with G_MALLOC
                                                                      mealsEaten[i] is how many meals philosopher i
                                                                      has consumed- used to prevent starvation*/

int* forks;
                                              /* shared data structure- must be allocated with G_MALLOC
                                                                      forks[i] represents the ith fork- this is to test that
                                                                      locks are working the way they should. Philosopher i
                                                                      has fork[i] on the left and fork[i+1] on the right
                                                                      (mod if necessary). forks[i]= 1 when the fork is in
                                                                      use, 0 otherwise. */


/* Variables that can be redefined from the command line */

/* Use: -l type
*        to set the lock type- choices are:(RC, SCC, NONE)
* -e min max
* to set the range for eating time- min max in milliseconds (use ints)
* -t min max
* to set the range for thinking time- min max in milliseconds (use ints)
* -life num
* to set the number of cycles for each philosopher's life
*/

/* the different types of locks so you can choose which kind to use */

enum LockType {RC, SCC, NONE};
enum LockType myLock= RC; /* default lock */

/* ranges for the amount of time the philosophers can
eat or think- uses a random number generator to get a time
in the range. defaults are 1 to 50 milliseconds. Could
be changed by a command line switch. min cannot equal max */

int eatingTimeMin= 1;
int eatingTimeMax= 1000;
int thinkingTimeMin= 1;
int thinkingTimeMax= 1000;

/* number of times each philosopher goes through his lifecycle */
int numberCycles= 8;

/* helper functions */

/* returns # of philosopher to the left of philosopher #i*/
int Left(int i) {
    return (NP+i-1) % NP;
}

/* returns # of philosopher to the right of philosopher #i*/
int Right(int i) {
    return (i+1)%NP;
}

/* functions to lock and unlock whatever type of lock was chosen */
void lock(enum LockType lt) {
    switch(lt) {
    case RC:
        RCLOCK(mutex);
        break;
    case SCC:
        SCCLOCK(mutex);
        break;
    case NONE:
        break;
    default:
        ERREXIT("invalid locking mechanism");
    }
}

void unlock(enum LockType lt) {

    switch(lt) {
    case RC:
        RCUNLOCK(mutex);
        break;
    case SCC:
        SCCUNLOCK(mutex);
        break;
    case NONE:
        break;
    default:
        ERREXIT("invalid locking mechanism");
    }
}

void lock(enum LockType lt) {
    switch(lt) {
    case RC:
        RCLOCK(mutex);
        break;
    case SCC:
        SCCLOCK(mutex);
        break;
    case NONE:
        break;
    default:
        ERREXIT("invalid locking mechanism");
    }
}

void unlock(enum LockType lt) {

    switch(lt) {
    case RC:
        RCUNLOCK(mutex);
        break;
    case SCC:
        SCCUNLOCK(mutex);
        break;
    case NONE:
        break;
    default:
        ERREXIT("invalid locking mechanism");
    }
}

/* does the appropriate writes for any kind of lock */
void PickUpForksWrite(enum LockType mylock, int i) {
    if (mylock == SCC) {
       
/* SCC locks need special writes */

       
/* take the forks */
        SccWriteInt((char*)&forks[i], forks[i] + 1);
        SccWriteInt((char*)&forks[Right(i)], forks[Right(i)] + 1);
        OUTPUT("Philosopher #%d has picked up the forks\n", i);
       
       
/* decrement fork counts of left and right neighbors */
        SccWriteInt((char*)&freeForks[Left(i)], freeForks[Left(i)] - 1);
        SccWriteInt((char*) &freeForks[Right(i)], freeForks[Right(i)] - 1);

       
/* increment total number of meals */
        SccWriteInt((char*) &mealsEaten[i], mealsEaten[i] + 1);
    }
    else {
       
/* take the forks */
        forks[i]++;
        forks[Right(i)]++;
        OUTPUT("Philosopher #%d has picked up the forks\n", i);
     
       
/* decrement fork counts of left and right neighbors */
        freeForks[Left(i)]--;
        freeForks[Right(i)]--;
        mealsEaten[i]++; /* increment number of meals */
    }
}

/* writes to the shared data structures - does the appropriate writes for any kind of lock */
void PutDownForksWrite(enum LockType mylock, int i) {
    if (mylock == SCC) {
        /* SCC locks require special write */
        SccWriteInt((char*)&forks[i], forks[i] - 1);
        SccWriteInt((char*)&forks[Right(i)], forks[Right(i)] - 1);
        OUTPUT("Philosopher #%d has released the forks\n", i);

        SccWriteInt((char*)&freeForks[Left(i)], freeForks[Left(i)] + 1);
        SccWriteInt((char*)&freeForks[Right(i)], freeForks[Right(i)] + 1);

    }
    else {
        forks[i]--;
        forks[Right(i)]--;
        OUTPUT("Philosopher #%d has released the forks\n", i);
       
       
/* increment fork counts of neighbors */
        freeForks[Left(i)]++;
        freeForks[Right(i)]++;
    }
}


/* philosopher functions*/

/* pick up both forks simultaneously, when both are available*/
void PickUp(int i) {
    while (1) {
        lock(myLock);
/* acquire mutual exclusion */
   
       
/* give up lock if both forks are not available, or if neighbor is starving */
        if ((freeForks[i] != 2) ||
            (mealsEaten[i] - mealsEaten[(Left(i))] > 3) ||
            (mealsEaten[i] - mealsEaten[(Right(i))] > 3))
        {
       
            unlock(myLock);
/* relinquish mutual exclusion */
        }
        else {
           
/* LOCK TEST!!! check if mutual exclusion was obeyed.*/
            if (forks[i] != 0 || forks[Right(i)] != 0) {
                ERREXIT("Philosopher #%d was allowed to pick up a fork already in use.", i);
            }
            else {
               
/* take the forks */
                   PickUpForksWrite(myLock, i);
            }
            unlock(myLock);
/* relinquish mutual exclusion */
            break;
        }
    }
}

void PutDown(i) {
    lock(myLock);
/* acquire mutual exclusion */

   
/* LOCK TEST!!! see if the mutual exclusion works */ /* LOCK TEST!!! see if the mutual exclusion works */
    if (forks[i] != 1 || forks[Right(i)] != 1) {
        ERREXIT("error in fork allocation- one culprit is Philosopher#%d\n", i);
    }
    else {
       
/* put forks down */
        PutDownForksWrite(myLock, i);
    }
    unlock(myLock);
/* relinquish mutual exclusion */
}

void Eat(int i) {
    int timeOut;
    int random;
    random= rand();

   
/* get the random number in the range*//* get the random number in the range*/
    timeOut= (random % (eatingTimeMax - eatingTimeMin))
        + eatingTimeMin;
    OUTPUT("Philosopher #%d is eating\n", i);

   
/*busy wait for awhile*/
    Sleep(timeOut);
}

void Think(int i) {
    int timeOut;
    int random;
    random= rand();
   
/* get the random number in the range*/
    timeOut= (random % (thinkingTimeMax - thinkingTimeMin))
        + thinkingTimeMin;
   
    OUTPUT("Philosopher #%d is thinking\n", i);

   
/* busy wait for awhile */
    Sleep(timeOut);
}

void Philosopher() {
    int MyId, j;

    GETMYGLOBALID(&MyId);
    OUTPUT("Philosopher #%d reporting for duty\n", MyId);
    BARRIER(0);
    j=0;
    while(j < numberCycles) {
        OUTPUT(">>>>>>>>>>>>>>>>>>Philosopher #%d in Cycle #%d\n",MyId, j);
      
        PickUp(MyId);   
        Eat(MyId);
        PutDown(MyId);
        Think(MyId);
        j++;
    }
    BARRIER(0);
}

void dining_main() {
    int i, myId;
   
/* seed the random number generator for eating and thinking time */
    srand( (unsigned)time( NULL ) );

    GETMYGLOBALID(&myId);

    if (myId == 0) {

       
/* G_MALLOC the shared memory */ /* G_MALLOC the shared memory */

        G_MALLOC((char*)freeForks, NUM_PHILOSOPHERS*sizeof(int));
        if (freeForks == 0) {
            ERREXIT("out of shared memory\n");
        }
   
        G_MALLOC((char*)mealsEaten, NUM_PHILOSOPHERS*sizeof(int));
        if (mealsEaten == 0) {
            ERREXIT("out of shared memory\n");
        }

        G_MALLOC((char*)forks, NUM_PHILOSOPHERS*sizeof(int));
        if (forks == 0) {
            ERREXIT("out of shared memory\n");
        }
       
       
/* initialize */
        for (i=0; i < NUM_PHILOSOPHERS; i++) {
            freeForks[i]=2;
            mealsEaten[i]=0;
            forks[i]=0;
        }
    }   
    BARRIER(0);

    Philosopher();
}

void main(int argc, char**argv) {
   
    int z, k, newtime;
    HANDLE philosophers[MAX_USER_THREADS_PER_NODE];
  
/* array of handles returned by Create_Thread */


    INITENV(argc, argv, 0); 
    NP = TOTAL_USER_THREADS;

   
/* parse the command line */
    for (z=1; z < ARGC; z++) {
       
        if (!strcmp(ARGV[z], "-l")) {
/* user picks which kind of lock */
            z++;

            if (!strcmp(ARGV[z],"RC")) {
                myLock=RC;
            }
            else {
                if (!strcmp(ARGV[z],"SCC")) {
                     myLock= SCC;
                }
                 else {
                    if (!strcmp(ARGV[z],"NONE")) {
                        myLock= NONE;
                    }
                    else {
                        ERREXIT("bad command line parameter for type of lock");
                    }
                }
            }
        }
       
        if (!strcmp(ARGV[z],"-e")) {
/* user picks range for eating time */
            z++;
            if (ARGV[z] != NULL) {
                newtime=atoi(ARGV[z]);
                eatingTimeMin= newtime;
                z++;
                if (ARGV[z] != NULL) {
                    newtime= atoi(ARGV[z]);
                    eatingTimeMax=newtime;
                }
                else
                    ERREXIT("bad command line parameter for eating time max");
            }
            else {
                ERREXIT("bad command line parameter for eating time min");
            }
        }

        if (!strcmp(ARGV[z],"-t")) {
/* user picks range for thinking time */
            z++;
            if (ARGV[z] != NULL) {
                newtime=atoi(ARGV[z]);
                thinkingTimeMin= newtime;
                z++;
                if (ARGV[z] != NULL) {
                    newtime= atoi(ARGV[z]);
                    thinkingTimeMax=newtime;
                }
                else
                    ERREXIT("bad command line parameter for thinking time max");
            }
            else {
                ERREXIT("bad command line parameter for thinking time min");
            }
        }

        if (!strcmp(ARGV[z],"-life")) {
/* user picks how long the philosophers live- number of cycles, not units of time*/
            z++;
            if (ARGV[z] != NULL) {
                newtime=atoi(ARGV[z]);
                numberCycles= newtime;
            }
            else
                ERREXIT("bad command line parameter for life of philosophers");
        }
    }

   
/* now everything is ready- create the philosopher threads */ /* now everything is ready- create the philosopher threads */
    for (k=0; k < NUM_LOCAL_USER_THREADS; k++) {
        CREATE_THREAD(&philosophers[k], (DWORD) dining_main);
    }

   
/* everyone runs numberCycles times- wait until everyone is done */

    WaitForMultipleObjects(NUM_LOCAL_USER_THREADS, philosophers, TRUE, INFINITE);
   
    EXIT;
}