π₯ Letβs immortalize this one properly β itβs a clean, lethal, real-world philo
monitor core β the kind that deserves its own 10_philosophers_monitor_heartbeat note.
Hereβs the asymmetric FAANG-grade breakdown:
π½οΈ 10_philosophers_monitor_heartbeat
π§ A time-sensitive death monitor loop that catches if any philosopher hasnβt eaten for
TIME_TO_DIE
ms
β°οΈ This is wherephilosophers
stops being about threads and starts being about scheduling, starvation, and heartbeat expiry.
π Core pattern used in:
OS thread watchdogs
Distributed consensus timeouts
Real-time systems
βοΈ Overview
π‘ Goal
-
Launch
PHILO_COUNT
threads (philo_routine
) -
Each philosopher:
-
π Eats
-
π€ Thinks
-
π Updates their
last_meal
timestamp
-
-
Meanwhile, the monitor:
-
π§ Checks every millisecond
-
π If
now - last_meal > TIME_TO_DIE
β thread declared dead -
π Ends the simulation
-
π© Constants
#define PHILO_COUNT 5
#define TIME_TO_DIE 3000
#define EAT_TIME 1000
#define THINK_TIME 500
β³ This means:
-
Each philo must eat every 3000ms or less
-
Eating + Thinking takes 1500ms total, so should be safe
-
But if anything delays them β the monitor will catch it
π¦ Struct: t_philo
typedef struct s_philo
{
int id;
long last_meal;
pthread_mutex_t meal_mutex;
} t_philo;
Each philosopher tracks:
-
π§ Their ID
-
π Their last known mealtime (ms)
-
π Their own lock around meal access
β Per-philo mutex prevents monitor/data race on
last_meal
π§΅ Thread Behavior
π½οΈ Philosopher Routine
while (simulation_running)
{
pthread_mutex_lock(&philo->meal_mutex);
philo->last_meal = get_time_ms();
pthread_mutex_unlock(&philo->meal_mutex);
printf("Philo %d is eating...\n", philo->id);
usleep(EAT_TIME * 1000);
printf("philo %d is thinking...\n", philo->id);
usleep(THINK_TIME * 1000);
}
π The philo:
Updates
last_meal
BEFORE eatingDoesnβt care if it dies (no awareness of simulation ending)
Runs until monitor kills the simulation
π§ Monitor Routine
while (simulation_running)
{
usleep(1000);
for each philo:
lock(meal_mutex)
now = get_time_ms();
if (now - last_meal > TIME_TO_DIE)
kill sim
unlock
}
β Checks each philoβs last_meal time
β Sleeps every 1ms for resolution
β Kills the simulation on the first expired thread
π Failure Model Simulated
π Event | π§ Response |
---|---|
Philo is slow | β Monitor detects timeout |
Philo starves | β Simulation stops |
Multiple dead? | β First one triggers kill β rest ignored |
Edge case: Philo stops updating last_meal | π Will be caught |
π§ Why This Is Asymmetric
title: Asymmetric System Traits
- β±οΈ Simulates **real-time failure detection**
- π Philosophers are oblivious; monitor acts like a separate OS thread
- π§ Teaches **timeout correctness**: your thread may be alive, but still too late
- 𧬠Clean structure, yet tightly race-sensitive (if you forget mutexes = undefined)
- π³οΈ Exposes hidden delay traps: `usleep()` precision drift can cause deaths
π Critical Learning Points
π§ Pattern | π Danger |
---|---|
β
pthread_mutex_lock before checking timestamps | β Prevents reading half-written values |
β
usleep(1000) in monitor | β Simulates fine-grained polling β but real schedulers may drift |
β Writing to last_meal without mutex | π£ Will pass testβ¦ until it doesnβt |
β Forgetting to join(monitor) | π Threads will keep running even if one dies |
β Stopping threads cleanly | β Simulation ends, but philo threads may still print after death |
π§ͺ Suggested Asymmetric Variants
π₯ [[asymmetric_pthreads/10b_heartbeat_delay_death_demo.c]]
β Inject `usleep()` randomizer to simulate philosopher lag
π [[asymmetric_pthreads/10c_monitor_starves_itself.c]]
β Let monitor use mutexes badly β dies in lock-wait
π [[asymmetric_pthreads/10d_philosopher_self_awareness.c]]
β Each philo detects its own timeout and self-terminates
π§ TL;DR Summary
title: Pulse Monitor Design Pattern
- β
Launch background `monitor` to watch for missed heartbeats
- π Poll shared timestamps protected by per-thread mutex
- β οΈ Kill simulation if any philosopher starves
- π§΅ Classic for distributed systems, kernel schedulers, watchdogs
- π₯ High reward, high subtlety: race-safe logic, async-safe loop, and clear failure path
Ready for [[10b_heartbeat_delay_death_demo.c]]
or a proper queue version of philosopher forks?
We can make the death signal propagate like a virus across threads.