Skip to content
Snippets Groups Projects
Commit f63894f5 authored by Mactavish's avatar Mactavish
Browse files

remove old exercises

parent 071bbfbb
No related branches found
No related tags found
No related merge requests found
PROG = simple_deadlock
OBJECTS = simple_deadlock.o
CC = gcc
CFLAGS = -Wall -std=c11 -pthread
CFLAGS += -I. # add the current directory to the include path
.Phone: all
all: clean $(PROG) # build and run the program
./$(PROG)
$(PROG): $(OBJECTS) # link the object files into a binary
$(CC) $(CFLAGS) $^ -o $@
$(OBJECTS): %.o: %.c # compile the source files into object files
$(CC) $(CFLAGS) -c $<
.PHONY: clean
clean: # remove the object files and the binary
rm -f $(OBJECTS) $(PROG)
# Simple deadlock
Here is a small exercise that helps you understand common deadlock situation in C.
## Instructions
Read through the source code in `simple_deadlock.c`, try to run it multiple times.
Then fix the code that causes the deadlock. Recompile it and run it again.
## Build
```bash
# build and run the executable
make
# clean all compilation files
make clean
```
#include <pthread.h>
#include <stdio.h>
const int SIZE = 10;
pthread_mutex_t g_mutex, even_mutex, odd_mutex;
void shared_print_thread_even(int i) {
pthread_mutex_lock(&even_mutex);
pthread_mutex_lock(&odd_mutex);
printf(" %d ", i);
pthread_mutex_unlock(&odd_mutex);
pthread_mutex_unlock(&even_mutex);
}
void shared_print_thread_odd(int i) {
pthread_mutex_lock(&even_mutex);
pthread_mutex_lock(&odd_mutex);
printf(" %d ", i);
pthread_mutex_unlock(&odd_mutex);
pthread_mutex_unlock(&even_mutex);
}
void shared_print_main(int i) {
pthread_mutex_lock(&g_mutex);
printf(" %d ", i);
pthread_mutex_unlock(&g_mutex);
}
void *f(void *arg) {
int n = *(int *)arg;
for (int i = SIZE * (n - 1); i < SIZE * n; i++) {
if (n % 2 == 0)
shared_print_thread_even(i);
else
shared_print_thread_odd(i);
}
return NULL;
}
int main() {
pthread_t t1, t2, t3, t4, t5;
// Initialize the mutexes
pthread_mutex_init(&g_mutex, NULL);
pthread_mutex_init(&even_mutex, NULL);
pthread_mutex_init(&odd_mutex, NULL);
int t1_arg = 1, t2_arg = 2, t3_arg = 3, t4_arg = 4, t5_arg = 5;
// Create the threads
pthread_create(&t1, NULL, f, &t1_arg);
pthread_create(&t2, NULL, f, &t2_arg);
pthread_create(&t3, NULL, f, &t3_arg);
pthread_create(&t4, NULL, f, &t4_arg);
pthread_create(&t5, NULL, f, &t5_arg);
for (int i = -1; i > -SIZE; i--)
shared_print_main(i);
// Wait for the threads to finish
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
pthread_join(t5, NULL);
// Destroy the mutexes
pthread_mutex_destroy(&g_mutex);
pthread_mutex_destroy(&even_mutex);
pthread_mutex_destroy(&odd_mutex);
return 0;
}
PROG = main
OBJECTS = main.o semaphore.o
CC = gcc
CFLAGS = -Wall -std=c11 -pthread
CFLAGS += -I. # add the current directory to the include path
.Phone: all
all: clean $(PROG) # build and run the program
./$(PROG)
$(PROG): $(OBJECTS) # link the object files into a binary
$(CC) $(CFLAGS) $^ -o $@
$(OBJECTS): %.o: %.c semaphore.h # compile the source files into object files
$(CC) $(CFLAGS) -c $<
.PHONY: clean
clean: # remove the object files and the binary
rm -f $(OBJECTS) $(PROG)
# Semaphore implementation
Here is a small exercise that helps you understand semaphore and conditional variables better.
## Instructions
First, go through all function declarations in `semaphore.h`. Then, go through `main.c` to see how these functions are used in the test program.
You will need to implement the following functions:
- `sem_init`: initialize the internal data for your semaphore implementation
- `sem_wait`: allow the access of a thread into the critical section and decrement the counter, or put the thread into a waiting queue.
- `sem_post`: increment the counter by 1, and signal the waiting threads in the queue if any.
- `sem_destory`: clean up all the data you've used.
## Hints
Read the man page about [condition variables](https://man7.org/linux/man-pages/man3/pthread_cond_wait.3p.html)
## Build
```bash
# build and run the executable
make
# clean all compilation files
make clean
```
#include <stdio.h>
#include <unistd.h>
#include "semaphore.h"
// Example usage
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
semaphore sem;
void* thread_function(void* arg) {
int id = *((int*)arg);
int i = 5;
sem_wait(&sem);
pthread_mutex_lock(&mutex);
printf("Thread %d enters\n", id);
pthread_mutex_unlock(&mutex);
sleep(1);
pthread_mutex_lock(&mutex);
printf("Thread %d quits\n", id);
pthread_mutex_unlock(&mutex);
sem_post(&sem);
pthread_exit(NULL);
}
int main() {
int num_threads = 10;
pthread_t threads[num_threads];
int thread_args[num_threads];
sem_init(&sem, 3); // Initialize semaphore with count 2
// Create threads
for (int i = 0; i < num_threads; i++) {
thread_args[i] = i;
pthread_create(&threads[i], NULL, thread_function, &thread_args[i]);
}
// Wait for threads to finish
for (int i = 0; i < num_threads; i++) {
pthread_join(threads[i], NULL);
}
sem_destroy(&sem); // Clean up semaphore
return 0;
}
#include "semaphore.h"
void sem_init(semaphore *sem, int count) {
sem->count = count;
pthread_mutex_init(&sem->mutex, NULL);
pthread_cond_init(&sem->condition, NULL);
}
void sem_wait(semaphore *sem) {
pthread_mutex_lock(&sem->mutex);
while (sem->count <= 0) {
pthread_cond_wait(&sem->condition, &sem->mutex);
}
sem->count--;
pthread_mutex_unlock(&sem->mutex);
}
void sem_post(semaphore *sem) {
pthread_mutex_lock(&sem->mutex);
sem->count++;
pthread_cond_signal(&sem->condition);
pthread_mutex_unlock(&sem->mutex);
}
void sem_destroy(semaphore *sem) {
pthread_mutex_destroy(&sem->mutex);
pthread_cond_destroy(&sem->condition);
}
#include <pthread.h>
typedef struct {
int count;
pthread_mutex_t mutex;
pthread_cond_t condition;
} semaphore;
void sem_init(semaphore *sem, int count);
void sem_wait(semaphore *sem);
void sem_post(semaphore *sem);
void sem_destroy(semaphore *sem);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment