dining-philosophers/DiningPhilosophers.c
2022-10-03 03:45:50 -05:00

172 lines
5.4 KiB
C

#include <pthread.h>
#include <semaphore.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define THINKING 0 /*philosopher is thinking*/
#define HUNGRY 1 /*philosopher is trying to get forks*/
#define EATING 2 /*philosopher is eating*/
typedef struct PhilosopherData
{
int eatingCount;
int position;
int state;
pthread_t thread;
} PhilosopherData;
sem_t semaphore;
bool AllPhilosophersFull(PhilosopherData PhilosopherList[], int numPhilosophers);
void PhilosopherWait();
void Eat(PhilosopherData* philosopherSelected);
int GetPhilosopherCount(char* argv);
void* Philosopher(void* philosopherPassed);
void PhilosopherInit(int philosopherTotal);
void PhilosopherListInit(PhilosopherData PhilosopherList[], int philosopherTotal);
void PutForks(PhilosopherData* philosopherSelected);
void TakeForks(PhilosopherData* philosopherSelected);
bool PhilosopherCanEat(PhilosopherData PhilosopherList[], int selectedPosition, int philosopherTotal);
void Think(PhilosopherData* philosopherSelected);
void AllowPhilosopher();
int main(int argc, char* argv[])
{
if (argc < 2)
printf("Too few arguments, exiting...\n");
if (argc > 2)
printf("Too many arguments, exiting...\n");
if (argc == 2)
{
int philosopherTotal;
philosopherTotal = GetPhilosopherCount(argv[1]);
PhilosopherInit(philosopherTotal);
}
return 0;
}
// Takes in array of times each philosopher has eaten
// If all philosophers have ate twice, then returns true
// Otherwise, if a philosopher has not eaten twice, returns false
bool AllPhilosophersFull(PhilosopherData PhilosopherList[], int numPhilosophers)
{
for (int i = 0; i < numPhilosophers; i++)
if (PhilosopherList[i].eatingCount < 2)
return false;
return true;
}
// Philosopher enters critical section.
void PhilosopherWait()
{
sem_wait(&semaphore);
}
// Sets philosopher to eating state and increments eating count.
void Eat(PhilosopherData* philosopherSelected)
{
printf("Philosopher %d is eating...\n", philosopherSelected->position);
philosopherSelected->state = EATING;
++philosopherSelected->eatingCount;
}
// Converts char* to number.
int GetPhilosopherCount(char* argv)
{
int philosopherTotal;
sscanf(argv, "%d", &philosopherTotal);
return philosopherTotal;
}
// Main function that each thread runs.
void* Philosopher(void* philosopherPassed)
{
PhilosopherData *philosopherSelected = (PhilosopherData*) philosopherPassed;
while (true)
{
if (philosopherSelected->eatingCount > 2)
{
// printf("Philosopher %d ate twice...\n", philosopherSelected->position);
return;
}
TakeForks(philosopherSelected); /*acquire two forks or block*/
Eat(philosopherSelected); /*yum-yum, spaghetti*/
PutForks(philosopherSelected); /*put both forks back on table*/
Think(philosopherSelected); /*philosopher is thinking*/
}
}
// Handles all philosopher threads, finishes when all philosophers are full.
void PhilosopherInit(int philosopherTotal)
{
PhilosopherData PhilosopherList[philosopherTotal];
PhilosopherListInit(PhilosopherList, philosopherTotal);
sem_init(&semaphore, 0, 1);
while (!AllPhilosophersFull(PhilosopherList, philosopherTotal))
{
sleep(1);
AllowPhilosopher();
}
sleep(5);
for (int i = 0; i < philosopherTotal; i++)
{
printf("Philosopher %d eating count: %d\n", PhilosopherList[i].position, PhilosopherList[i].eatingCount);
}
}
// Initializes full list of philosophers.
void PhilosopherListInit(PhilosopherData PhilosopherList[], int philosopherTotal)
{
for (int i = 0; i < philosopherTotal; i++)
{
PhilosopherList[i].position = i;
PhilosopherList[i].eatingCount = 0;
PhilosopherList[i].state = THINKING;
printf("Philosopher %d is thinking...\n", i);
pthread_create(&PhilosopherList[i].thread, NULL, &Philosopher, &PhilosopherList[i]);
}
}
// Philosopher puts forks down.
void PutForks(PhilosopherData* philosopherSelected)
{
printf("Philosopher %d is putting forks down...\n", philosopherSelected->position);
}
// Philosopher takes the forks on the left and right.
void TakeForks(PhilosopherData* philosopherSelected)
{
philosopherSelected->state = HUNGRY;
printf("Philosopher %d is hungry...\n", philosopherSelected->position);
PhilosopherWait();
}
// If philosopher is hungry and forks are free, then returns true.
// Else, philosopher returns false.
// Left philosopher math: (i+N-1)%N Right philosopher math: (i+1)%N
bool PhilosopherCanEat(PhilosopherData PhilosopherList[], int selectedPosition, int philosopherTotal)
{
if (PhilosopherList[selectedPosition].state != HUNGRY)
return false;
for (int i = 0; i < philosopherTotal; i++)
if (PhilosopherList[i].state == EATING)
return false;
return true;
}
// Philosopher begins thinking
void Think(PhilosopherData* philosopherSelected)
{
printf("Philosopher %d is thinking...\n", philosopherSelected->position);
philosopherSelected->state = THINKING;
}
// Philosopher exits critical section
void AllowPhilosopher()
{
sem_post(&semaphore);
}