Skip to main content

Overview

The Philosophers project uses two primary data structures to manage the simulation: t_philo for individual philosopher state and t_table for shared resources and global state.

The t_philo Structure

The t_philo struct represents an individual philosopher and contains all the data needed for their execution.
typedef struct s_philo
{
    pthread_t   thread;
    int         id;
    int         eating;
    int         meal_counter;
    int         max_meal;
    long        last_meal_time;
    long        start_time;
    long        nbr_philo;
    long        time_to_die;
    long        time_to_eat;
    long        time_to_sleep;
    int         *dead;
    t_mtx       *lock_dead;
    t_mtx       *lock_write;
    t_mtx       *lock_meal;
    t_mtx       *left_fork;
    t_mtx       *right_fork;
}       t_philo;

Field Documentation

FieldTypeDescription
threadpthread_tThe POSIX thread handle for this philosopher
idintUnique identifier for the philosopher (1-indexed)
FieldTypeDescription
eatingintFlag indicating if philosopher is currently eating (1) or not (0)
meal_counterintNumber of meals this philosopher has completed
max_mealintMaximum meals required (-1 if unlimited)
FieldTypeDescription
last_meal_timelongTimestamp (ms) of when the philosopher last started eating
start_timelongTimestamp (ms) when the simulation began
time_to_dielongMaximum time (ms) a philosopher can go without eating
time_to_eatlongDuration (ms) it takes to eat
time_to_sleeplongDuration (ms) the philosopher sleeps
FieldTypeDescription
nbr_philolongTotal number of philosophers at the table
deadint*Pointer to shared death flag (0=alive, 1=simulation ended)
lock_deadt_mtx*Mutex protecting the dead flag
lock_writet_mtx*Mutex protecting console output
lock_mealt_mtx*Mutex protecting meal-related data
left_forkt_mtx*Pointer to the left fork mutex
right_forkt_mtx*Pointer to the right fork mutex
Each philosopher holds pointers to shared mutexes rather than owning them directly. This allows multiple philosophers to coordinate access to shared resources.

The t_table Structure

The t_table struct manages global state and shared resources for the entire simulation.
typedef struct s_table
{
    int     dead_flag;
    t_mtx   lock_dead;
    t_mtx   lock_write;
    t_mtx   lock_meal;
    t_philo *philos;
}       t_table;

Field Documentation

FieldTypeDescription
dead_flagintGlobal flag: 0 means simulation running, 1 means terminated
lock_deadt_mtxMutex protecting access to dead_flag
lock_writet_mtxMutex serializing console output to prevent interleaving
lock_mealt_mtxMutex protecting meal counters and eating state
philost_philo*Array of all philosopher structures
The t_table owns the actual mutex objects, while individual t_philo structs hold pointers to these mutexes.

Initialization

Table Initialization

The init_data function initializes the table structure and its mutexes:
void    init_data(t_table *table, t_philo *philos)
{
    table->dead_flag = 0;
    table->philos = philos;
    pthread_mutex_init(&table->lock_write, NULL);
    pthread_mutex_init(&table->lock_dead, NULL);
    pthread_mutex_init(&table->lock_meal, NULL);
}
Source: init_data.c:66

Philosopher Initialization

The init_philos function initializes each philosopher with their unique state and shared resource pointers:
void    init_philos(t_philo *philos, t_table *table, t_mtx *forks,
        char **argv)
{
    int i;

    i = 0;
    while (i < ft_atoi(argv[1]))
    {
        philos[i].id = i + 1;
        philos[i].meal_counter = 0;
        philos[i].eating = 0;
        init_input(&philos[i], argv);
        philos[i].start_time = get_current_time();
        philos[i].last_meal_time = get_current_time();
        philos[i].lock_write = &table->lock_write;
        philos[i].lock_dead = &table->lock_dead;
        philos[i].lock_meal = &table->lock_meal;
        philos[i].dead = &table->dead_flag;
        philos[i].left_fork = &forks[i];
        if (i == 0)
            philos[i].right_fork = &forks[philos[i].nbr_philo - 1];
        else
            philos[i].right_fork = &forks[i - 1];
        i++;
    }
}
Source: init_data.c:27

Fork Assignment Logic

philos[i].left_fork = &forks[i];
philos[i].right_fork = &forks[i - 1];
Each philosopher’s left fork is at their own index, and their right fork is at the previous index.
This circular fork assignment ensures that each philosopher shares their right fork with the philosopher to their right, creating the classic dining philosophers problem topology.

Fork Initialization

Forks are represented as an array of mutexes, initialized separately:
void    init_forks(t_mtx *forks, int philo_num)
{
    int i;

    i = 0;
    while (i < philo_num)
    {
        pthread_mutex_init(&forks[i], NULL);
        i++;
    }
}
Source: init_data.c:54

Memory Layout

Table
├── dead_flag (int)
├── lock_dead (mutex)
├── lock_write (mutex)
├── lock_meal (mutex)
└── philos* → [Philosopher Array]
                ├── philos[0] → left_fork: &forks[0], right_fork: &forks[n-1]
                ├── philos[1] → left_fork: &forks[1], right_fork: &forks[0]
                ├── philos[2] → left_fork: &forks[2], right_fork: &forks[1]
                └── ...

Forks Array
├── forks[0] ← shared by philos[0] and philos[1]
├── forks[1] ← shared by philos[1] and philos[2]
└── ...
This structure ensures thread-safe access to shared state while minimizing contention between philosophers.

Build docs developers (and LLMs) love