dining-philosophers/DiningPhilosophers.c

168 lines
5.5 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;
sem_t semaphore;
int state;
pthread_t thread;
} PhilosopherData;
bool AllPhilosophersFull(PhilosopherData PhilosopherList[], int numPhilosophers);
void Down(sem_t* semaphore);
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 Up(sem_t* semaphore);
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 Down(sem_t* semaphore)
{
sem_wait(semaphore);
printf("A semaphore was put into waiting...\n");
}
// 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)
{
Think(philosopherSelected); /*philosopher is thinking*/
TakeForks(philosopherSelected); /*acquire two forks or block*/
Eat(philosopherSelected); /*yum-yum, spaghetti*/
PutForks(philosopherSelected); /*put both forks back on table*/
}
}
// Handles all philosopher threads, finishes when all philosophers are full.
void PhilosopherInit(int philosopherTotal)
{
PhilosopherData PhilosopherList[philosopherTotal];
PhilosopherListInit(PhilosopherList, philosopherTotal);
while (!AllPhilosophersFull(PhilosopherList, philosopherTotal))
{
for (int i = 0; i < philosopherTotal; i++)
{
if (PhilosopherCanEat(PhilosopherList, i, philosopherTotal))
{
Up(&(PhilosopherList[i].semaphore));
}
}
}
}
// 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;
sem_init(&PhilosopherList[i].semaphore, 0, 1);
pthread_create(&PhilosopherList[i].thread, NULL, &Philosopher, &PhilosopherList[i]);
pthread_join(PhilosopherList[i].thread, NULL);
}
}
// 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)
{
printf("Philosopher %d is taking forks...\n", philosopherSelected->position);
Down(&philosopherSelected->semaphore);
}
// 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;
int leftPhilosopher = (selectedPosition + (philosopherTotal-1)) % philosopherTotal;
int rightPhilosopher = (selectedPosition + 1) % philosopherTotal;
if (PhilosopherList[leftPhilosopher].state == EATING)
return false;
if (PhilosopherList[rightPhilosopher].state == EATING)
return false;
return true;
}
// Philosopher begins thinking
void Think(PhilosopherData* philosopherSelected)
{
philosopherSelected->state = THINKING;
printf("Philosopher %d is thinking...\n", philosopherSelected->position);
}
// Philosopher exits critical section
void Up(sem_t* semaphore)
{
sem_post(semaphore);
printf("A semaphore was released...\n");
}