philosophers_prep/rendu/philosophers_args.c

384 lines
8.7 KiB
C

/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* philosophers_args.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: ruiferna <ruiferna@student.42porto.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/10/12 00:00:00 by ruiferna #+# #+# */
/* Updated: 2025/10/12 01:23:53 by ruiferna ### ########.fr */
/* */
/* ************************************************************************** */
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
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);
}