diff --git a/C/main.c b/C/main.c index 0ca8fc2dcd9fed577f235f68e9f7582d5f36e4b3..005bedb6b11bcdbe7d5e099bead8045ba5b47e30 100644 --- a/C/main.c +++ b/C/main.c @@ -5,7 +5,7 @@ * Author: Brandon Rodriguez * * - * <File Description Here> + * Logic to implement "Peterson's Algorithm" in C. */ @@ -15,7 +15,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> #include <unistd.h> @@ -25,6 +24,12 @@ void *thread_a_method(); void *thread_b_method(); +// Global Variables (For shared thread values). +int* shared_flag; // Flag part of Peterson's Algorithm thread locking. +int shared_turn; // Turn part of Peterson's Algorithm thread locking. +int shared_counter; // Shared counter for threads to modify. Used to test that locking works. + + /** * Program's main. Initialized and runs program. */ @@ -43,49 +48,101 @@ int main(int argc, char* argv[]) { * Function to create and manage threads. */ void run_threads() { - printf("Starting threads...\n\n"); - // Declare variables. - pthread_t* thread_pool; + pthread_t* thread_pool = NULL; + void* thread_a_return; + void* thread_b_return; + int thread_a_result; + int thread_b_result; - srand(time(NULL)); + printf("Starting threads...\n\n"); - // Create threads. + // Create threads and threading values. thread_pool = calloc(2, sizeof(pthread_t)); - pthread_create(&thread_pool[0], NULL, thread_a_method, NULL); - pthread_create(&thread_pool[1], NULL, thread_b_method, NULL); - - // Join threads. - pthread_join(thread_pool[0], NULL); - pthread_join(thread_pool[1], NULL); - - printf("\nThreads terminated.\n"); + shared_flag = calloc(2, sizeof(int)); + pthread_create(&thread_pool[0], NULL, thread_a_method, (void*) &thread_a_result); + pthread_create(&thread_pool[1], NULL, thread_b_method, (void*) &thread_b_result); + + // Wait for threads to finish. + pthread_join(thread_pool[0], &thread_a_return); + pthread_join(thread_pool[1], &thread_b_return); + + printf("\nThreads Results.\n"); + printf(" Shared counter: %d\n", shared_counter); + printf(" A: %d\n", *(int*) thread_a_return); + printf(" B: %d\n\n", *(int*) thread_b_return); + + // Free allocated variables. + free(thread_pool); + free(shared_flag); } /** * Function for thread "a" to run. */ -void *thread_a_method() { - int random = rand() % 5; - printf("Random int is: %d\n", random); - sleep(random); +void *thread_a_method(void* results) { + printf("Entering thread \"a\" method.\n"); + + // Set to be other thread's turn. + shared_flag[0] = 1; + shared_turn = 1; + + // Loop on a sleep command until it's this thread's turn. + while (shared_flag[1] && shared_turn == 1); - printf("Thread a running.\n"); + // If we made it this far, then it's this thread's turn. + // Enter critical section. + printf("Entering thread \"a\" critical section.\n"); - return NULL; + // Loop through and add 100 to counter. + for (int index = 0; index < 100; index++) { + shared_counter += 1; + } + + // Copy current value of counter. + memcpy(results, &shared_counter, sizeof(int)); + + printf("Exiting thread \"a\" critical section.\n"); + // Critical section over. + // Set to be other thread's turn. + shared_flag[0] = 0; + + printf("Exiting thread \"a\" method.\n"); + return (void*) results; } /** * Function for thread "b" to run. */ -void *thread_b_method() { - int random = rand() % 5; - printf("Random int is: %d\n", random); - sleep(random); +void *thread_b_method(void* results) { + printf("Entering thread \"b\" method.\n"); + + // Set to be other thread's turn. + shared_flag[1] = 1; + shared_turn = 0; + + // Loop on a sleep command until it's this thread's turn. + while (shared_flag[0] && shared_turn == 0); + + // If we made it this far, then it's this thread's turn. + // Enter critical section. + printf("Entering thread \"b\" critical section.\n"); + + // Loop through and add 100 to counter. + for (int index = 0; index < 100; index++) { + shared_counter += 1; + } + + // Copy current value of counter. + memcpy(results, &shared_counter, sizeof(int)); - printf("Thread b running.\n"); + printf("Exiting thread \"b\" critical section.\n"); + // Critical section over. + // Set to be other thread's turn. + shared_flag[1] = 0; - return NULL; + printf("Exiting thread \"b\" method.\n" + return (void*) results; } diff --git a/documents/c_references.md b/documents/c_references.md index f887f80ae17c90f966d11619f997e645719ddc22..4979dac8af305836298c0678c9d8188bf4601f16 100644 --- a/documents/c_references.md +++ b/documents/c_references.md @@ -7,9 +7,14 @@ All references to external logic. Includes anything from stack overflow links to ## References +### Refresher on C Pointers +* <https://www.tutorialspoint.com/cprogramming/c_pointers.htm> + ### MultiThreading in C * Since it's been a while since I used the C language, I referenced my old CS4540 (Operating Systems) project, both to try to remember how C works and as an example of how PThreads work. Project is located at <https://git.brandon-rodriguez.com/c/cs_4540/a4>. * General MultiThreading - <https://www.geeksforgeeks.org/multithreading-c-2/> +* Returning a value from a thread - <https://stackoverflow.com/a/2251472> +* Copying variable at current state, before other threads touch it - <https://www.geeksforgeeks.org/memcpy-in-cc/> ### Getting a Random Int in C * <https://www.geeksforgeeks.org/rand-and-srand-in-ccpp/>