This project has been created as part of the 42 curriculum by gaabekas.
Codexion is a programme demonstrating the use of concurrent threads using shared memory. In this implementation of the 'Dining Philosophers Problem', coders share USB dongles and should be compiling, refactoring, debugging without burning out. The programme accepts parameters and outputs the coders' actions in real time.
To compile, enter the project's working folder, and in the terminal, type make.
To run the programme, type the name of the programme ./codexion followed by the following parameters in this order in a digit format:
- number of coders
- time to burnout
- time to compile
- time to debug
- time to refactor
- number of compiles required
- dongle cooldown
As well as the chosen scheduler in a text format:
fifooredf.
Here is an example:
./codexion 4 2000 100 50 50 2 10 fifo
- Dining Philosophers Problem — Wikipedia
- POSIX Threads documentation (pthread_create, pthread_mutex, pthread_cond)
AI (Claude & Chat GPT) was used throughout the project as a learning companion, specifically:
- Understanding concurrency concepts (deadlock, starvation, Coffman conditions, data races)
- Debugging
All code was written by gaabekas.
Deadlock is prevented by atomic acquisition: a coder acquires both dongles at once or none at all, under a single mutex. A coder never holds one dongle while waiting for the other, which breaks the "hold and wait" condition (one of Coffman's four conditions for deadlock).
Starvation occurs when a coder never gets access to dongles and burns out. This is prevented by a priority queue (min-heap) that determines which coder gets to compile next. Before a coder can acquire dongles, the function higher_priority_can_go checks whether any higher-priority coder sharing the same dongles could go instead. If so, the coder waits. Under FIFO, priority is based on request arrival time - the coder who requested first goes first. Under EDF, priority is based on burnout deadline - the coder closest to burning out goes first, which provides stronger starvation prevention.
A data race occurs when two threads access the same memory at the same time, and at least one of them writes to it. In this project, shared data includes last_compile_time, compile_count, simulation_over, the heap, and the log output. All accesses to these shared variables are protected by mutexes (simulation_mutex for coder/monitor shared data, log_mutex for logging and simulation_over). A thread must lock the relevant mutex before reading or writing, and unlock it after - any other thread trying to access the same data must wait until the mutex is released.
If two threads call printf at the same time, their output can interleave on the same line, producing unreadable logs. To prevent this, all log messages go through the logging function, which locks log_mutex before printing and unlocks it after. This guarantees that each log line is printed completely before another thread can print.
A separate monitor thread checks all coders every 5ms. A coder has burned out if the current time minus their last_compile_time exceeds time_to_burnout. The 5ms interval guarantees that burnout is detected and logged within the 10 ms tolerance required by the subject.
After a dongle is released, it cannot be taken again until dongle_cooldown milliseconds have passed. This prevents a coder from immediately re-acquiring the same dongles, giving other coders a chance to make their requests. The cooldown_check function calculates when each dongle's cooldown expires, takes the later of the two (since both dongles are needed), and if the cooldown is not yet finished, uses pthread_cond_timedwait to sleep until the expiry time before re-checking all conditions.
This project uses the following POSIX threading primitives:
pthread_t: each coder and the monitor run as separate threads created withpthread_create.pthread_mutex_t: two mutexes are used.simulation_mutexprotects shared coder data (last_compile_time,compile_count) and dongle state.log_mutexprotects log output andsimulation_over.pthread_cond_t: a condition variable (dongle_cond) allows coder threads to sleep while waiting for dongles, instead of busy-waiting. When a coder releases dongles,pthread_cond_broadcastwakes all sleeping coders so they can re-check their conditions.pthread_cond_timedwait: used for dongle cooldown - a coder sleeps until the cooldown expires, then re-checks all conditions.