lab: added solutions

This commit is contained in:
Daniel Meiburg 2024-12-16 01:21:02 +01:00
parent 8b3abe2dde
commit a5c25c64f9
Signed by: dm
GPG Key ID: E5827ECFFE0AA4F2
5 changed files with 376 additions and 17 deletions

View File

@ -3,32 +3,39 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#define DEBUG 1
#define ITERATIONS 100000 #define ITERATIONS 100000
// Shared variables // Shared variables
pthread_mutex_t lock; pthread_mutex_t lock;
pthread_cond_t cond; pthread_cond_t cond;
int signal_flag = 0; // 0 = LOW, 1 = HIGH int state_flag = 0; // 0 = LOW, 1 = HIGH
int counter = 0; int counter = 0;
void* high_thread(void* arg) {
void* high_thread() {
while (1) { while (1) {
pthread_mutex_lock(&lock); pthread_mutex_lock(&lock);
if (counter >= ITERATIONS) {
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond);
return NULL;
}
// Wait for turn // Wait for turn
while (signal_flag != 1) { while (state_flag != 1) {
pthread_cond_wait(&cond, &lock); pthread_cond_wait(&cond, &lock);
} }
// Critical section // Critical section
if (counter >= ITERATIONS) { #if DEBUG
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond);
exit(0);
}
printf("%d: HIGH\n", counter); printf("%d: HIGH\n", counter);
#endif
counter++; counter++;
signal_flag = 0; state_flag = 0; // Switch to LOW
// Signal the other thread // Signal the other thread
pthread_mutex_unlock(&lock); pthread_mutex_unlock(&lock);
@ -37,24 +44,27 @@ void* high_thread(void* arg) {
return NULL; return NULL;
} }
void* low_thread(void* arg) { void* low_thread() {
while (1) { while (1) {
pthread_mutex_lock(&lock); pthread_mutex_lock(&lock);
if (counter >= ITERATIONS) {
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond);
return NULL;
}
// Wait for turn // Wait for turn
while (signal_flag != 0) { while (state_flag != 0) {
pthread_cond_wait(&cond, &lock); pthread_cond_wait(&cond, &lock);
} }
// Critical section // Critical section
if (counter >= ITERATIONS) { #if DEBUG
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond);
exit(0);
}
printf("%d: LOW\n", counter); printf("%d: LOW\n", counter);
#endif
counter++; counter++;
signal_flag = 1; state_flag = 1; // Switch to HIGH
// Signal the other thread // Signal the other thread
pthread_mutex_unlock(&lock); pthread_mutex_unlock(&lock);
@ -74,6 +84,11 @@ int main() {
pthread_create(&high_tid, NULL, high_thread, NULL); pthread_create(&high_tid, NULL, high_thread, NULL);
pthread_create(&low_tid, NULL, low_thread, NULL); pthread_create(&low_tid, NULL, low_thread, NULL);
#if DEBUG
printf("Start threads:\n");
#endif
// Wait for threads to finish // Wait for threads to finish
pthread_join(high_tid, NULL); pthread_join(high_tid, NULL);
pthread_join(low_tid, NULL); pthread_join(low_tid, NULL);

View File

@ -0,0 +1,51 @@
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#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;
}

View File

@ -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 <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <time.h>
#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, &timestamps[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;
}

View File

@ -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 <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#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;
}

114
lab/square_wave_timed.c Normal file
View File

@ -0,0 +1,114 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#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, &timestamps[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, &timestamps[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;
}