/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* philosophers_args.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: ruiferna +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/10/12 00:00:00 by ruiferna #+# #+# */ /* Updated: 2025/10/12 01:23:53 by ruiferna ### ########.fr */ /* */ /* ************************************************************************** */ #include #include #include #include #include #include typedef struct s_philo { int id; int meals_eaten; long long last_meal_time; pthread_mutex_t meal_mutex; struct s_shared *shared; } t_philo; typedef struct s_shared { int num_philos; int time_to_die; int time_to_eat; int time_to_sleep; int must_eat_count; int has_must_eat; int simulation_stop; long long start_time; pthread_mutex_t *forks; pthread_mutex_t printf_mutex; pthread_mutex_t stop_mutex; t_philo *philos; } t_shared; long long get_current_time(void) { struct timeval tv; gettimeofday(&tv, NULL); return ((tv.tv_sec * 1000LL) + (tv.tv_usec / 1000LL)); } void precise_sleep(int ms) { long long start_time; start_time = get_current_time(); while ((get_current_time() - start_time) < ms) usleep(100); } void print_message(t_shared *shared, int philo_id, char *message) { long long timestamp; pthread_mutex_lock(&shared->stop_mutex); if (!shared->simulation_stop) { pthread_mutex_unlock(&shared->stop_mutex); pthread_mutex_lock(&shared->printf_mutex); timestamp = get_current_time() - shared->start_time; printf("%lld %d %s\n", timestamp, philo_id, message); pthread_mutex_unlock(&shared->printf_mutex); } else pthread_mutex_unlock(&shared->stop_mutex); } int check_stop(t_shared *shared) { int stop; pthread_mutex_lock(&shared->stop_mutex); stop = shared->simulation_stop; pthread_mutex_unlock(&shared->stop_mutex); return (stop); } void philo_eat(t_philo *philo) { int left_fork; int right_fork; int first; int second; left_fork = philo->id - 1; right_fork = philo->id % philo->shared->num_philos; first = left_fork; second = right_fork; if (first > second) { first = right_fork; second = left_fork; } pthread_mutex_lock(&philo->shared->forks[first]); print_message(philo->shared, philo->id, "has taken a fork"); if (philo->shared->num_philos == 1) { pthread_mutex_unlock(&philo->shared->forks[first]); return ; } pthread_mutex_lock(&philo->shared->forks[second]); print_message(philo->shared, philo->id, "has taken a fork"); pthread_mutex_lock(&philo->meal_mutex); philo->last_meal_time = get_current_time(); pthread_mutex_unlock(&philo->meal_mutex); print_message(philo->shared, philo->id, "is eating"); precise_sleep(philo->shared->time_to_eat); pthread_mutex_lock(&philo->meal_mutex); philo->meals_eaten++; pthread_mutex_unlock(&philo->meal_mutex); pthread_mutex_unlock(&philo->shared->forks[second]); pthread_mutex_unlock(&philo->shared->forks[first]); } void *philo_routine(void *arg) { t_philo *philo; philo = (t_philo *)arg; if (philo->id % 2 == 0) precise_sleep(50); while (!check_stop(philo->shared)) { print_message(philo->shared, philo->id, "is thinking"); philo_eat(philo); if (check_stop(philo->shared)) break ; print_message(philo->shared, philo->id, "is sleeping"); precise_sleep(philo->shared->time_to_sleep); } return (NULL); } int check_death(t_shared *shared) { int i; long long current_time; long long time_since_meal; i = 0; while (i < shared->num_philos) { pthread_mutex_lock(&shared->philos[i].meal_mutex); current_time = get_current_time(); time_since_meal = current_time - shared->philos[i].last_meal_time; pthread_mutex_unlock(&shared->philos[i].meal_mutex); if (time_since_meal > shared->time_to_die) { pthread_mutex_lock(&shared->stop_mutex); shared->simulation_stop = 1; pthread_mutex_unlock(&shared->stop_mutex); pthread_mutex_lock(&shared->printf_mutex); printf("%lld %d died\n", current_time - shared->start_time, shared->philos[i].id); pthread_mutex_unlock(&shared->printf_mutex); return (1); } i++; } return (0); } int check_all_ate(t_shared *shared) { int i; int all_done; if (!shared->has_must_eat) return (0); i = 0; all_done = 1; while (i < shared->num_philos) { pthread_mutex_lock(&shared->philos[i].meal_mutex); if (shared->philos[i].meals_eaten < shared->must_eat_count) all_done = 0; pthread_mutex_unlock(&shared->philos[i].meal_mutex); i++; } if (all_done) { pthread_mutex_lock(&shared->stop_mutex); shared->simulation_stop = 1; pthread_mutex_unlock(&shared->stop_mutex); return (1); } return (0); } void *monitor_routine(void *arg) { t_shared *shared; shared = (t_shared *)arg; while (!check_stop(shared)) { if (check_death(shared)) break ; if (check_all_ate(shared)) break ; usleep(1000); } return (NULL); } int ft_atoi(const char *str) { int result; int i; result = 0; i = 0; while (str[i] >= '0' && str[i] <= '9') { result = result * 10 + (str[i] - '0'); i++; } return (result); } int is_valid_number(const char *str) { int i; i = 0; if (!str || str[0] == '\0') return (0); while (str[i]) { if (str[i] < '0' || str[i] > '9') return (0); i++; } return (1); } int parse_arguments(int argc, char **argv, t_shared *shared) { if (argc != 5 && argc != 6) { printf("Usage: %s number_of_philosophers time_to_die time_to_eat time_to_sleep [number_of_times_must_eat]\n", argv[0]); return (0); } if (!is_valid_number(argv[1]) || !is_valid_number(argv[2]) || !is_valid_number(argv[3]) || !is_valid_number(argv[4])) return (0); shared->num_philos = ft_atoi(argv[1]); shared->time_to_die = ft_atoi(argv[2]); shared->time_to_eat = ft_atoi(argv[3]); shared->time_to_sleep = ft_atoi(argv[4]); if (shared->num_philos <= 0 || shared->time_to_die <= 0 || shared->time_to_eat <= 0 || shared->time_to_sleep <= 0) return (0); if (argc == 6) { if (!is_valid_number(argv[5])) return (0); shared->must_eat_count = ft_atoi(argv[5]); if (shared->must_eat_count <= 0) return (0); shared->has_must_eat = 1; } else shared->has_must_eat = 0; return (1); } int init_shared(t_shared *shared) { int i; shared->simulation_stop = 0; shared->forks = malloc(sizeof(pthread_mutex_t) * shared->num_philos); if (!shared->forks) return (0); shared->philos = malloc(sizeof(t_philo) * shared->num_philos); if (!shared->philos) { free(shared->forks); return (0); } i = 0; while (i < shared->num_philos) { pthread_mutex_init(&shared->forks[i], NULL); i++; } pthread_mutex_init(&shared->printf_mutex, NULL); pthread_mutex_init(&shared->stop_mutex, NULL); return (1); } void init_philosophers(t_shared *shared) { int i; long long current_time; current_time = get_current_time(); shared->start_time = current_time; i = 0; while (i < shared->num_philos) { shared->philos[i].id = i + 1; shared->philos[i].meals_eaten = 0; shared->philos[i].last_meal_time = current_time; shared->philos[i].shared = shared; pthread_mutex_init(&shared->philos[i].meal_mutex, NULL); i++; } } void cleanup(t_shared *shared, pthread_t *threads) { int i; i = 0; while (i < shared->num_philos) { pthread_mutex_destroy(&shared->forks[i]); pthread_mutex_destroy(&shared->philos[i].meal_mutex); i++; } pthread_mutex_destroy(&shared->printf_mutex); pthread_mutex_destroy(&shared->stop_mutex); free(shared->forks); free(shared->philos); free(threads); } int main(int argc, char **argv) { t_shared shared; pthread_t *threads; pthread_t monitor; int i; memset(&shared, 0, sizeof(t_shared)); if (!parse_arguments(argc, argv, &shared)) { printf("Error: Invalid arguments\n"); return (1); } if (!init_shared(&shared)) { printf("Error: Initialization failed\n"); return (1); } init_philosophers(&shared); threads = malloc(sizeof(pthread_t) * shared.num_philos); if (!threads) { cleanup(&shared, NULL); return (1); } i = 0; while (i < shared.num_philos) { pthread_create(&threads[i], NULL, philo_routine, &shared.philos[i]); i++; } pthread_create(&monitor, NULL, monitor_routine, &shared); i = 0; while (i < shared.num_philos) { pthread_join(threads[i], NULL); i++; } pthread_join(monitor, NULL); cleanup(&shared, threads); return (0); }