Skip to content
This repository was archived by the owner on Apr 20, 2026. It is now read-only.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This project has been created as part of the 42 curriculum by vsoares-

philosophers

Description

The philosophers project is part of the 42 curriculum and focuses on concurrent programming, synchronization, and thread/process coordination.

The goal is to solve the classic Dining Philosophers Problem: several philosophers alternate between thinking, eating, and sleeping while sharing a limited number of forks. The challenge is to design the simulation so that:

  • data races are avoided through proper mutex synchronization,
  • deadlocks are prevented via careful fork acquisition ordering,
  • starvation is handled according to project rules with continuous monitoring,
  • timing and state transitions are correctly monitored and displayed.

This project is mainly about learning how to build safe, deterministic behavior in a multithreaded environment and understanding common pitfalls in concurrent systems.

Instructions

Requirements

  • A C compiler (cc/gcc/clang)
  • make
  • POSIX threads support (pthread)

Compilation

From the project root, run:

make

Common targets (if available in your Makefile):

  • make → build the executable
  • make clean → remove object files
  • make fclean → remove object files and executable
  • make re → full rebuild

Execution

Run the program with:

./philo number_of_philosophers time_to_die time_to_eat time_to_sleep [number_of_times_each_philosopher_must_eat]

Example:

./philo 5 800 200 200

Where:

  • number_of_philosophers: number of philosophers (and forks)
  • time_to_die: max time (ms) a philosopher can stay without eating
  • time_to_eat: time (ms) spent eating
  • time_to_sleep: time (ms) spent sleeping
  • number_of_times_each_philosopher_must_eat (optional): stop when each philosopher has eaten at least this many times

Argument Validation

The program validates all input arguments before starting the simulation:

  • Argument Count: Requires exactly 4 or 5 arguments
  • Argument Type: All arguments must be valid positive integers
  • Zero Check: Number of philosophers, time values, and meal counts cannot be zero
  • Value Constraints: Time values (time_to_die, time_to_eat, time_to_sleep) must be greater than zero

If any validation fails, the program exits with an appropriate error message.

Implementation Details

Synchronization Architecture

The simulation uses a multi-layered mutex system to prevent data races:

  • Global Mutexes (4 total):

    • death_mutex: Protects the shared death state and meal count limits
    • narrator_mutex: Synchronizes output to prevent interleaved print statements
    • start_time_mutex: Protects the simulation start timestamp
    • sim_started_mutex: Ensures all threads wait for synchronization before beginning
  • Spoon/Fork Mutexes (N total, one per philosopher):

    • Each fork is represented as a t_spoon with its own mutex
    • Philosophers must acquire both adjacent forks before eating
  • Philosopher Mutexes (N total, one per philosopher):

    • Each philosopher's state (last meal time, meal count, death status) is protected

This design ensures that:

  • Fork state is exclusively accessed by at most one philosopher at a time
  • Death detection and announcements don't race
  • Output messages are atomic and correctly ordered

Fork Acquisition Strategy

Philosophers acquire forks based on their ID parity to prevent circular wait deadlocks:

  • Even-ID Philosophers (0, 2, 4, ...):

    • Pick fork at position id first (first_spoon)
    • Then pick fork at position (id + 1) % num_philos (second_spoon)
  • Odd-ID Philosophers (1, 3, 5, ...):

    • Pick fork at position (id + 1) % num_philos first (first_spoon)
    • Then pick fork at position id (second_spoon)

This ordering breaks the circular dependency that would otherwise cause deadlocks.

Special Handling for Odd Philosopher Counts

When the number of philosophers is odd, the simulation requires special initialization:

  • Philosopher 0's Initial Think Period: Before entering the main eat-sleep-think cycle, philosopher 0 waits for 2 * time_to_eat milliseconds. This gives other philosophers time to acquire forks and prevents an immediate bottleneck.

  • Dynamic Think Time Calculation: For each philosopher during normal cycles, if 2 * time_to_eat > time_to_sleep, the system calculates:

    time_to_think = (2 * time_to_eat) - time_to_sleep
    

    This ensures philosophers don't wake up too quickly from sleep and starve others waiting for forks.

  • Even-ID Initial Think: Even-ID philosophers (except 0) also think for time_to_eat milliseconds before their first eating attempt, ensuring staggered fork acquisition.

Starvation Detection and Monitoring

The monitoring system continuously checks for starvation:

  1. Per-Philosopher Monitoring: Each philosopher tracks its last_meal_time
  2. Death Check: If (current_time - last_meal_time) >= time_to_die, the philosopher is marked dead
  3. Single Death Announcement: The first philosopher to die has its death printed exactly once to the output
  4. Simulation End: The monitoring loop exits when either:
    • A philosopher dies, OR
    • All philosophers have eaten number_of_times_each_philosopher_must_eat times (if specified)

Action Narration

The narration system ensures atomic, correctly-ordered output:

  • Thread-Safe Printing: All output is protected by narrator_mutex to prevent interleaved messages
  • Death Announcement: Death messages are announced exactly once using a static flag, even if multiple threads detect starvation
  • Simulation End Detection: Non-death messages are suppressed after the simulation ends (either due to death or meal completion)
  • Timestamps: Each message includes milliseconds elapsed since simulation start

Notes

  • Timestamps are shown in milliseconds from simulation start.
  • The simulation ends when a philosopher dies, or when the optional meal count condition is met and all philosophers are full.
  • Use small/large timing values carefully when testing edge cases.

Resources

References

Concept & Theory:

Man Pages (Linux man-pages):

AI usage disclosure

AI was used as a support tool for:

  • reviewing README structure and clarity,
  • improving wording and documentation quality,
  • checking consistency of command descriptions and parameter explanations.

AI was not used to replace project understanding or core implementation decisions. Final validation, code logic, and project behavior remain the author's responsibility.

Additional Information

Project structure (typical)

The repository usually contains:

  • source files for philosopher logic, timing, and synchronization,
  • a Makefile for building the executable,
  • this README.md for setup and project context,
  • en.philosophers.pdf - English version of the 42 philosophers project specification.

Suggested tests

  • Minimal valid case (e.g., 1 philosopher)
  • Typical case (e.g., 2–5 philosophers)
  • Stress case with many philosophers (up to 200)
  • Cases near timing limits to validate death detection and race safety
  • Odd vs. even philosopher counts to verify special initialization logic

About

42 philosophers project

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages