Dining Philosophers: C Example Andréa M. Matsunaga & Maurício
O. Tsugawa |
/* 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;
}