/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* simple_philosophers.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: ruiferna +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/10/09 11:16:23 by ruiferna #+# #+# */ /* Updated: 2025/10/09 18:58:45 by ruiferna ### ########.fr */ /* */ /* ************************************************************************** */ #include "simple_philosophers.h" #define PHILOS 3 #define FORKS 3 typedef struct s_shared { int philos; int alive; pthread_mutex_t alive_mutex; pthread_mutex_t philo_mutex; pthread_mutex_t printf_lock; pthread_mutex_t forks[FORKS]; } t_shared; void message(long long timestamp, int id, char *action, pthread_mutex_t *mutex) { pthread_mutex_lock(mutex); printf("[%lld] Philosopher %i is %s.\n", timestamp, id, action); // printf("%lld %i %s\n", timestamp, id, action); pthread_mutex_unlock(mutex); } void *philo_routine(void *arg) { t_shared *shared; int philo_id; long long timestamp; shared = (t_shared *) arg; timestamp = get_current_time(); pthread_mutex_lock(&shared->philo_mutex); shared->philos += 1; /* convert to 0-based id for indexing forks */ philo_id = shared->philos - 1; pthread_mutex_unlock(&shared->philo_mutex); /* small stagger to reduce simultaneous contention: odd threads sleep briefly */ if (philo_id % 2 == 1) precise_sleep(50); while (1) { /* check alive flag */ pthread_mutex_lock(&shared->alive_mutex); if (!shared->alive) { pthread_mutex_unlock(&shared->alive_mutex); break; } pthread_mutex_unlock(&shared->alive_mutex); message(get_current_time()-timestamp, philo_id + 1, "thinking", &shared->printf_lock); precise_sleep(1000); int left = philo_id; int right = (philo_id + 1) % FORKS; int first = left; int second = right; if (first > second) { int tmp = first; first = second; second = tmp; } pthread_mutex_lock(&shared->forks[first]); message(get_current_time()-timestamp, philo_id + 1, "grabbed first fork", &shared->printf_lock); /* try to grab the second fork; if unavailable, release first and retry/check alive */ if (pthread_mutex_trylock(&shared->forks[second]) != 0) { /* couldn't get second fork: release first and go back to loop */ pthread_mutex_unlock(&shared->forks[first]); message(get_current_time()-timestamp, philo_id + 1, "released first fork", &shared->printf_lock); /* brief pause with per-philosopher jitter to reduce contention */ precise_sleep(10 + ((philo_id * 37) % 50)); /* check alive before continuing */ pthread_mutex_lock(&shared->alive_mutex); if (!shared->alive) { pthread_mutex_unlock(&shared->alive_mutex); break; } pthread_mutex_unlock(&shared->alive_mutex); continue; } message(get_current_time()-timestamp, philo_id + 1, "grabbed second fork", &shared->printf_lock); message(get_current_time()-timestamp, philo_id + 1, "eating", &shared->printf_lock); precise_sleep(1000); pthread_mutex_unlock(&shared->forks[first]); message(get_current_time()-timestamp, philo_id + 1, "released first fork", &shared->printf_lock); pthread_mutex_unlock(&shared->forks[second]); message(get_current_time()-timestamp, philo_id + 1, "released second fork", &shared->printf_lock); } return (NULL); } void *monitor_routine(void *arg) { t_shared *shared = (t_shared *)arg; /* run for 10 seconds then flip alive to 0 */ precise_sleep(10000); pthread_mutex_lock(&shared->alive_mutex); shared->alive = 0; pthread_mutex_unlock(&shared->alive_mutex); return NULL; } int main() { pthread_t *philos; t_shared shared; pthread_t monitor; pthread_mutex_init(&shared.philo_mutex, NULL); pthread_mutex_init(&shared.printf_lock, NULL); pthread_mutex_init(&shared.alive_mutex, NULL); /* initialize fork mutexes */ for (int i = 0; i < FORKS; ++i) pthread_mutex_init(&shared.forks[i], NULL); shared.philos = 0; shared.alive = 1; /* allocate correct size for pthread_t array */ philos = malloc(sizeof(pthread_t) * PHILOS); int i = 0; while (i < PHILOS) { pthread_create(&philos[i++], NULL, philo_routine, &shared); } /* start monitor to stop after 10 seconds */ pthread_create(&monitor, NULL, monitor_routine, &shared); i = 0; while (i < PHILOS) { pthread_join(philos[i++], NULL); } /* wait for monitor (it may have already finished) */ pthread_join(monitor, NULL); /* cleanup */ for (int j = 0; j < FORKS; ++j) pthread_mutex_destroy(&shared.forks[j]); pthread_mutex_destroy(&shared.philo_mutex); pthread_mutex_destroy(&shared.printf_lock); pthread_mutex_destroy(&shared.alive_mutex); free(philos); return (0); }