diff --git a/main.c b/main.c index d7079b65368ce3c6cc4231e4105888b4bd009dfb..5e094d57b32c99f3f78af1c567d6e52a352cf6ac 100755 --- a/main.c +++ b/main.c @@ -20,12 +20,14 @@ // Variable Declaration. -pthread_mutex_t mutex_lock; +pthread_mutex_t left_fork_lock; +pthread_mutex_t right_fork_lock; bool all_ready; // Indicates that all philosophers are ready and at table. bool* thread_ready; // Indicates which individual philosophers are ready. bool* fork_ready; // Indicates fork of given index is ready for pickup. -bool* forks; // Indicates fork of given index is currently held. - +int* fork_held_by; // Indicates fork of given index is currently by which thread. +int* last_output; // Last status output for philosopher. +int philosopher_count; // Number of philosophers at table. // Method Declaration. void* start_thread(); @@ -38,24 +40,30 @@ void release_forks(); * Initializes and runs program. */ int main(int argc, char* argv[]) { - printf("Starting program.\n"); + printf("Starting program.\n\n"); // Create variables. - pthread_t* thread_array = calloc(10, sizeof(pthread_t)); - int* thread_results = calloc(10, sizeof(int)); + philosopher_count = 10; + pthread_t* thread_array = calloc(philosopher_count, sizeof(pthread_t)); + int* thread_results = calloc(philosopher_count, sizeof(int)); int index = 0; all_ready = false; - thread_ready = calloc(10, sizeof(bool)); - fork_ready = calloc(10, sizeof(bool)); + thread_ready = calloc(philosopher_count, sizeof(bool)); + fork_ready = calloc(philosopher_count, sizeof(bool)); + fork_held_by = calloc(philosopher_count, sizeof(int)); + last_output = calloc(philosopher_count, sizeof(int)); - while (index < 10) { + while (index < philosopher_count) { thread_ready[index] = false; + fork_ready[index] = true; + fork_held_by[index] = -1; + last_output[index] = 0; index += 1; } // Create threads. index = 0; - while (index < 10) { + while (index < philosopher_count) { // Create new "thread_number" int from index and save to new memory location. Then create thread. int* thread_number = calloc(1, sizeof(int)); *thread_number = index; @@ -65,7 +73,7 @@ int main(int argc, char* argv[]) { // Wait until all threads initialize. Aka, all philosophers sit down at the table. index = 0; - while (index < 10) { + while (index < philosopher_count) { while (thread_ready[index] == false) { sleep(0.5); } @@ -73,11 +81,21 @@ int main(int argc, char* argv[]) { } printf("All philosophers are ready. Time to eat.\n\n"); all_ready = true; - free(thread_ready); - // Philosophers are eating. On finish, join threads and handle results. + + // Philosophers are eating. Wait until they're all done. + index = 0; + while (index < philosopher_count) { + while (thread_ready[index] == true) { + sleep(0.5); + } + index += 1; + } + printf("\nAll philosophers have finished eating.\n"); + + // All philosophers are ready to leave the table. join threads and handle results. index = 0; - while (index < 10) { + while (index < philosopher_count) { // Get and save return value. Free original pointer for int that was passed into threads. void* ret_val = NULL; pthread_join(thread_array[index], &ret_val); @@ -88,11 +106,14 @@ int main(int argc, char* argv[]) { } // Free variables. + free(last_output); + free(fork_held_by); free(fork_ready); + free(thread_ready); free(thread_array); free(thread_results); - printf("\n\nTerminating program.\n"); + printf("\nTerminating program.\n"); } @@ -110,18 +131,33 @@ void* start_thread(void* thread_num) { // Everyone is ready and present. Start eating. int bites_taken = 0; - while (bites_taken < 10000) { - pthread_mutex_lock(&mutex_lock); - bites_taken += 1; - pthread_mutex_unlock(&mutex_lock); + int left_fork = *(int*) thread_num; + int right_fork = (*(int*) thread_num + 1) % philosopher_count; + // while (bites_taken < 10) { + while (bites_taken < 1000) { + + // Attempt to get forks. + get_forks(*(int*) thread_num, left_fork, right_fork); + + // Only eat if philosopher has two forks. + if (fork_held_by[left_fork] == *(int*) thread_num && fork_held_by[right_fork] == *(int*) thread_num) { + bites_taken += 1; + sleep(0.0001); + } + + // Attempt to release forks. + release_forks(*(int*) thread_num, left_fork, right_fork); - if ((bites_taken % 1000) == 0) { + if (bites_taken > last_output[*(int*) thread_num] && (bites_taken % 100) == 0) { printf("Philosopher #%d has taken %d bites. Resting.\n", *(int*) thread_num, bites_taken); - sleep(1); + last_output[*(int*) thread_num] = bites_taken; + sleep(0.9); } + } printf("Philosopher #%d is full.\n", *(int*) thread_num); + thread_ready[*(int*) thread_num] = false; pthread_exit(thread_num); } @@ -129,14 +165,49 @@ void* start_thread(void* thread_num) { /** * Function to attempt to get forks. Must have two forks to eat. */ -void get_forks(int thread_num) { +void get_forks(int thread_num, int left_fork, int right_fork) { + // Attempt to get left fork. + pthread_mutex_lock(&left_fork_lock); + if (fork_ready[left_fork]) { + fork_ready[left_fork] = false; + fork_held_by[left_fork] = thread_num; + } + pthread_mutex_unlock(&left_fork_lock); + // Attempt to get right fork. + pthread_mutex_lock(&right_fork_lock); + if (fork_ready[right_fork]) { + fork_ready[right_fork] = false; + fork_held_by[right_fork] = thread_num; + } + pthread_mutex_unlock(&right_fork_lock); + + // Check if philosopher got both forks. + if (fork_held_by[left_fork] != thread_num || fork_held_by[right_fork] != thread_num) { + // Failed to get one or more forks. Release if any were picked up. + // printf("Philosopher #%d could not get both forks. Releasing.\n", thread_num); + release_forks(thread_num, left_fork, right_fork); + } } /** * Function to release all held forks. */ -void release_forks(int thread_num) { +void release_forks(int thread_num, int left_fork, int right_fork) { + // Release left fork. + pthread_mutex_lock(&left_fork_lock); + if (fork_held_by[left_fork] == thread_num) { + fork_held_by[left_fork] = -1; + fork_ready[left_fork] = true; + } + pthread_mutex_unlock(&left_fork_lock); + // Release right fork. + pthread_mutex_lock(&right_fork_lock); + if (fork_held_by[right_fork] == thread_num) { + fork_held_by[right_fork] = -1; + fork_ready[right_fork] = true; + } + pthread_mutex_unlock(&right_fork_lock); } diff --git a/makefile b/makefile index 162f452313aa70249b5b2c026c882c0773b7beb7..433c21444f6652770164312a2f322f0581fd205f 100755 --- a/makefile +++ b/makefile @@ -2,7 +2,7 @@ # Tell makefile to use commands define here, if file with same name exists. .PHONY: all compile run valgrind clean # Set default if none is specified. -default: valgrind clean +default: run clean # Fully build and execute project. @@ -32,7 +32,7 @@ clean: # Display help output. help: - @echo "Default: Executes \"valgrind\", then \"clean\"." + @echo "Default: Executes \"run\", then \"clean\"." @echo "" @echo "Available Commands:" @echo " all - Executes \"run\", then \"clean\"."