diff --git a/lab/square_wave.c b/lab/square_wave.c index 4ca5ec0..ad5af2e 100644 --- a/lab/square_wave.c +++ b/lab/square_wave.c @@ -3,32 +3,39 @@ #include #include +#define DEBUG 1 + #define ITERATIONS 100000 // Shared variables pthread_mutex_t lock; pthread_cond_t cond; -int signal_flag = 0; // 0 = LOW, 1 = HIGH +int state_flag = 0; // 0 = LOW, 1 = HIGH int counter = 0; -void* high_thread(void* arg) { + +void* high_thread() { while (1) { + pthread_mutex_lock(&lock); + if (counter >= ITERATIONS) { + pthread_mutex_unlock(&lock); + pthread_cond_signal(&cond); + return NULL; + } + // Wait for turn - while (signal_flag != 1) { + while (state_flag != 1) { pthread_cond_wait(&cond, &lock); } // Critical section - if (counter >= ITERATIONS) { - pthread_mutex_unlock(&lock); - pthread_cond_signal(&cond); - exit(0); - } + #if DEBUG printf("%d: HIGH\n", counter); + #endif counter++; - signal_flag = 0; + state_flag = 0; // Switch to LOW // Signal the other thread pthread_mutex_unlock(&lock); @@ -37,24 +44,27 @@ void* high_thread(void* arg) { return NULL; } -void* low_thread(void* arg) { +void* low_thread() { while (1) { pthread_mutex_lock(&lock); + if (counter >= ITERATIONS) { + pthread_mutex_unlock(&lock); + pthread_cond_signal(&cond); + return NULL; + } + // Wait for turn - while (signal_flag != 0) { + while (state_flag != 0) { pthread_cond_wait(&cond, &lock); } // Critical section - if (counter >= ITERATIONS) { - pthread_mutex_unlock(&lock); - pthread_cond_signal(&cond); - exit(0); - } + #if DEBUG printf("%d: LOW\n", counter); + #endif counter++; - signal_flag = 1; + state_flag = 1; // Switch to HIGH // Signal the other thread pthread_mutex_unlock(&lock); @@ -74,6 +84,11 @@ int main() { pthread_create(&high_tid, NULL, high_thread, NULL); pthread_create(&low_tid, NULL, low_thread, NULL); + + #if DEBUG + printf("Start threads:\n"); + #endif + // Wait for threads to finish pthread_join(high_tid, NULL); pthread_join(low_tid, NULL); diff --git a/lab/square_wave_semaphores.c b/lab/square_wave_semaphores.c new file mode 100644 index 0000000..875c0d1 --- /dev/null +++ b/lab/square_wave_semaphores.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#define DEBUG 1 +#define ITERATIONS 100000 + +sem_t high_sem, low_sem; +int counter = 0; + +void* high() { + while (counter < ITERATIONS) { + sem_wait(&high_sem); + #if DEBUG + printf("%d: HIGH\n", counter); + #endif + sem_post(&low_sem); + counter++; + } + return NULL; +} + +void* low() { + while (counter < ITERATIONS) { + sem_wait(&low_sem); + #if DEBUG + printf("%d: LOW\n", counter); + #endif + sem_post(&high_sem); + counter++; + } + return NULL; +} + +int main() { + pthread_t high_thread, low_thread; + + sem_init(&high_sem, 0, 1); // high_sem starts + sem_init(&low_sem, 0, 0); + + pthread_create(&high_thread, NULL, high, NULL); + pthread_create(&low_thread, NULL, low, NULL); + + pthread_join(high_thread, NULL); + pthread_join(low_thread, NULL); + + sem_destroy(&high_sem); + sem_destroy(&low_sem); + + return 0; +} diff --git a/lab/square_wave_semaphores_timed.c b/lab/square_wave_semaphores_timed.c new file mode 100644 index 0000000..0c2ae30 --- /dev/null +++ b/lab/square_wave_semaphores_timed.c @@ -0,0 +1,93 @@ +// Description: This program uses semaphores to create a square wave between two threads. +// The period of the square wave is timed and displayed after the threads have finished. + +#include +#include +#include +#include +#include + +#define DEBUG 0 +#define NUM_PERIODS 100e3 + +sem_t high_sem, low_sem; + +struct timespec start_time, end_time; + +// Array to store timestamps of each period +struct timespec timestamps[NUM_PERIODS]; + +void* high() { + for (int i = 0; i < NUM_PERIODS; i++) { + sem_wait(&high_sem); + + if (clock_gettime(CLOCK_MONOTONIC, ×tamps[i]) != 0) { + perror("clock_gettime failed"); + exit(1); + } + + #if DEBUG + printf("%d: HIGH\n", i); + #endif + sem_post(&low_sem); + + } + return NULL; +} + +void* low() { + for (int i = 0; i < NUM_PERIODS; i++) { + sem_wait(&low_sem); + #if DEBUG + printf("%d: LOW\n", i); + #endif + sem_post(&high_sem); + } + return NULL; +} + +int main() { + pthread_t high_thread, low_thread; + + sem_init(&high_sem, 0, 1); // high_sem starts + sem_init(&low_sem, 0, 0); + + pthread_create(&high_thread, NULL, high, NULL); + pthread_create(&low_thread, NULL, low, NULL); + + pthread_join(high_thread, NULL); + pthread_join(low_thread, NULL); + + sem_destroy(&high_sem); + sem_destroy(&low_sem); + + int period; + int min_period; + int max_period; + int sum_of_periods = 0; + + // Print periods for each iteration + for (int i = 1; i < NUM_PERIODS; i++) { + sum_of_periods += period; + period = (timestamps[i].tv_sec - timestamps[i - 1].tv_sec) * 1e9 + (timestamps[i].tv_nsec - timestamps[i - 1].tv_nsec); + if (i == 1) { + min_period = period; + max_period = period; + } else { + if (period < min_period) { + min_period = period; + } + if (period > max_period) { + max_period = period; + } + } + + //printf("Period %d: %lld nanoseconds\n", i, periods[i]); + //printf("%lld\n", periods[i]); + } + printf("Minimum period: %d nanoseconds\n", min_period); + printf("Maximum period: %d nanoseconds\n", max_period); + printf("Average period: %f nanoseconds\n", (float)sum_of_periods / (NUM_PERIODS - 1)); + + return 0; +} diff --git a/lab/square_wave_semaphores_timed_improved.c b/lab/square_wave_semaphores_timed_improved.c new file mode 100644 index 0000000..550f414 --- /dev/null +++ b/lab/square_wave_semaphores_timed_improved.c @@ -0,0 +1,86 @@ +// Description: This program uses semaphores to create a square wave between two threads. +// The period of the square wave is timed and displayed after the threads have finished. + +#include +#include +#include +#include + +#define DEBUG 0 +#define NUM_PERIODS 100000 + +sem_t high_sem, low_sem; + +struct timespec start_time, end_time; + +// Array to store periods +int periods[NUM_PERIODS]; + +void* high() { + for (int i = 0; i < NUM_PERIODS; i++) { + sem_wait(&high_sem); + + if (i != 0) { + // Calculate period + clock_gettime(CLOCK_MONOTONIC, &end_time); + periods[i] = (end_time.tv_sec - start_time.tv_sec) * 1e9 + (end_time.tv_nsec - start_time.tv_nsec); + } + clock_gettime(CLOCK_MONOTONIC, &start_time); + + #if DEBUG + printf("%d: HIGH\n", i); + #endif + sem_post(&low_sem); + + } + return NULL; +} + +void* low() { + for (int i = 0; i < NUM_PERIODS; i++) { + sem_wait(&low_sem); + #if DEBUG + printf("%d: LOW\n", i); + #endif + sem_post(&high_sem); + } + return NULL; +} + +int main() { + pthread_t high_thread, low_thread; + + sem_init(&high_sem, 0, 1); // high_sem starts + sem_init(&low_sem, 0, 0); + + pthread_create(&high_thread, NULL, high, NULL); + pthread_create(&low_thread, NULL, low, NULL); + + pthread_join(high_thread, NULL); + pthread_join(low_thread, NULL); + + sem_destroy(&high_sem); + sem_destroy(&low_sem); + + int min_period = periods[1]; + int max_period = periods[1]; + int sum_of_periods = 0; + + // Print periods for each iteration + for (int i = 1; i < NUM_PERIODS; i++) { + if (periods[i] < min_period) { + min_period = periods[i]; + } + if (periods[i] > max_period) { + max_period = periods[i]; + } + sum_of_periods += periods[i]; + //printf("Period %d: %lld nanoseconds\n", i, periods[i]); + //printf("%lld\n", periods[i]); + } + printf("Minimum period: %d nanoseconds\n", min_period); + printf("Maximum period: %d nanoseconds\n", max_period); + printf("Average period: %f nanoseconds\n", (float)sum_of_periods / (NUM_PERIODS - 1)); + + return 0; +} diff --git a/lab/square_wave_timed.c b/lab/square_wave_timed.c new file mode 100644 index 0000000..5786b5c --- /dev/null +++ b/lab/square_wave_timed.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +#define ITERATIONS 100000 + +// Shared variables +pthread_mutex_t lock; +pthread_cond_t cond; +int signal_flag = 0; // 0 = LOW, 1 = HIGH +int counter = 0; + +// set up an array of timespec structs to store timestamps +struct timespec timestamps[ITERATIONS]; + +void* high_thread(void* arg) { + while (1) { + + if (counter >= ITERATIONS) { + pthread_cond_signal(&cond); + return NULL; + } + + pthread_mutex_lock(&lock); + + // Wait for turn + while (signal_flag != 1) { + pthread_cond_wait(&cond, &lock); + } + #ifdef DEBUG + printf("%d: HIGH\n", counter); + #endif + counter++; + signal_flag = 0; + + if (clock_gettime(CLOCK_MONOTONIC, ×tamps[counter]) != 0) { + perror("clock_gettime failed"); + exit(1); + } + + // Signal the other thread + pthread_mutex_unlock(&lock); + pthread_cond_signal(&cond); + } + return NULL; +} + +void* low_thread(void* arg) { + while (1) { + if (counter >= ITERATIONS) { + pthread_cond_signal(&cond); + return NULL; + } + + pthread_mutex_lock(&lock); + + // Wait for turn + while (signal_flag != 0) { + pthread_cond_wait(&cond, &lock); + } + + #ifdef DEBUG + printf("%d: LOW\n", counter); + #endif + counter++; + signal_flag = 1; + + if (clock_gettime(CLOCK_MONOTONIC, ×tamps[counter]) != 0) { + perror("clock_gettime failed"); + exit(1); + } + + // Signal the other thread + pthread_mutex_unlock(&lock); + pthread_cond_signal(&cond); + } + return NULL; +} + +int main() { + pthread_t high_tid, low_tid; + + // Initialize synchronization primitives + pthread_mutex_init(&lock, NULL); + pthread_cond_init(&cond, NULL); + + // Create threads + pthread_create(&high_tid, NULL, high_thread, NULL); + pthread_create(&low_tid, NULL, low_thread, NULL); + + + printf("Start threads:\n"); + + // Wait for threads to finish + pthread_join(high_tid, NULL); + pthread_join(low_tid, NULL); + + // Cleanup + pthread_mutex_destroy(&lock); + pthread_cond_destroy(&cond); + + + for (int i = 1; i < ITERATIONS; i++) { + printf("Period %zu: %ld.%09ld seconds\n", + i, + timestamps[i].tv_sec - timestamps[i-1].tv_sec, + timestamps[i].tv_nsec) - timestamps[i-1].tv_nsec; + } + + return 0; +} +