philosophers

This commit is contained in:
2023-12-12 17:37:16 +01:00
commit d3e7bd98b5
13 changed files with 771 additions and 0 deletions

76
Makefile Executable file
View File

@@ -0,0 +1,76 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# Makefile :+: :+: :+: #
# +:+ +:+ +:+ #
# By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2023/10/23 16:10:39 by fgras-ca #+# #+# #
# Updated: 2023/10/23 16:10:46 by fgras-ca ### ########.fr #
# #
# **************************************************************************** #
LOGO = @echo " __, ____, ____, ____, ____ ____, ___, ____,";\
echo "(-| (-/_| (-| \ (-|_, (-|__) (-|_, (- / (-|_,";\
echo " _|__, _/ |, _|__/ _|__, _|__) _|__, _/__, _|__,";\
echo "( ( ( ( ( ( ( ("
RST = \033[0m
GRAY = \033[0;90m
RED = \033[0;91m
GREEN = \033[0;92m
YELLOW = \033[0;93m
BLUE = \033[0;94m
MAGENTA = \033[0;95m
CYAN = \033[0;96m
WHITE = \033[0;97m
ORANGE = \033[38;5;214m
NAME = philo
SRCS = main.c \
threads.c \
initialize.c \
time.c \
philos.c \
utils.c \
memory.c \
routine.c \
forks.c \
monitoring.c \
OBJS = $(SRCS:.c=.o)
CC = gcc
RM = rm -f
CFLAGS = -Wall -Werror -Wextra -g
all: $(NAME)
$(NAME): $(OBJS)
@echo "$(RED)Compilation philosopher... $(RST)"
@$(CC) $(CFLAGS) $(OBJS) -o $(NAME) -lpthread
@echo "$(GREEN)Compilation complete. $(ORANGE)Type "./philo" for the menu!!$(RST)"
$(LOGO)
t : $(NAME)
@echo "$(RED)Compilation philosopher with fsanitize... $(RST)"
@$(CC) $(CFLAGS) -fsanitize=thread $(OBJS) -o $(NAME) -lpthread
@echo "$(GREEN)Compilation complete. $(ORANGE)Type "./philo" for the menu!!$(RST)"
$(LOGO)
clean:
@echo "$(RED)Deleating files objects... $(RST)"
@$(RM) $(OBJS)
@echo "$(GREEN)files deleted!! $(RST)"
$(LOGO)
fclean: clean
@echo "$(RED)Deleting program... $(RST)"
@$(RM) $(NAME)
@echo "$(GREEN)files deleted!! $(RST)"
$(LOGO)
re: fclean all
.PHONY: all t clean fclean re

BIN
en.subject.pdf Normal file

Binary file not shown.

69
forks.c Executable file
View File

@@ -0,0 +1,69 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* forks.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 11:50:15 by fgras-ca #+# #+# */
/* Updated: 2023/10/23 16:09:52 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
static void single_philosopher(t_philo *philo)
{
pthread_mutex_lock(&philo->left_fork->mutex_fork);
print_action(philo, BLUE"has taken a fork🍴"RST, 0);
while (1)
{
pthread_mutex_lock(&philo->sim->end_mutex);
if (philo->sim->is_philosopher_dead)
{
pthread_mutex_unlock(&philo->sim->end_mutex);
break ;
}
pthread_mutex_unlock(&philo->sim->end_mutex);
}
pthread_mutex_unlock(&philo->left_fork->mutex_fork);
}
void take_forks(t_philo *philo)
{
if (philo->sim->num_philosophers == 1)
{
single_philosopher(philo);
return ;
}
usleep(300);
if (philo->id % 2 == 0)
{
pthread_mutex_lock(&philo->left_fork->mutex_fork);
print_action(philo, BLUE"has taken a fork🍴"RST, 0);
pthread_mutex_lock(&philo->right_fork->mutex_fork);
print_action(philo, BLUE"has taken a fork🍴"RST, 0);
}
else
{
pthread_mutex_lock(&philo->right_fork->mutex_fork);
print_action(philo, BLUE"has taken a fork🍴"RST, 0);
pthread_mutex_lock(&philo->left_fork->mutex_fork);
print_action(philo, BLUE"has taken a fork🍴"RST, 0);
}
philo->can_eat = 1;
}
void release_forks(t_philo *philo)
{
if (philo->can_eat)
{
pthread_mutex_unlock(&philo->left_fork->mutex_fork);
if (philo->sim->num_philosophers > 1)
{
pthread_mutex_unlock(&philo->right_fork->mutex_fork);
}
philo->can_eat = 0;
}
usleep(300);
}

60
initialize.c Executable file
View File

@@ -0,0 +1,60 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* initialize.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 11:54:03 by fgras-ca #+# #+# */
/* Updated: 2023/10/17 12:27:25 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
int initialize_default_values(t_simulation *sim)
{
sim->num_philosophers = 0;
sim->time_to_die = 0;
sim->time_to_eat = 0;
sim->time_to_sleep = 0;
sim->max_meals = 0;
sim->start_time = initialize_start_time();
sim->is_philosopher_dead = 0;
sim->simulation_end = 0;
pthread_mutex_init(&sim->print_mutex, NULL);
pthread_mutex_init(&sim->end_mutex, NULL);
return (0);
}
int args_values(t_simulation *sim, int argc, char **argv)
{
if (argc < 5 || argc > 6)
{
pthread_mutex_lock(&sim->print_mutex);
printf(RED"Usage: %s num_philosophers time_to_die "
"time_to_eat time_to_sleep [max_meals]\n" RST, argv[0]);
pthread_mutex_unlock(&sim->print_mutex);
exit (EXIT_FAILURE);
}
else
{
sim->num_philosophers = ft_atoi(argv[1]);
sim->time_to_die = ft_atoi(argv[2]);
sim->time_to_eat = ft_atoi(argv[3]);
sim->time_to_sleep = ft_atoi(argv[4]);
if (argc == 6)
{
sim->max_meals = ft_atoi(argv[5]);
}
}
return (0);
}
int initialize_simulation(t_simulation *sim, int argc, char **argv)
{
initialize_default_values(sim);
args_values(sim, argc, argv);
initialize_philosophers(sim);
return (0);
}

23
main.c Executable file
View File

@@ -0,0 +1,23 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* main.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 12:28:04 by fgras-ca #+# #+# */
/* Updated: 2023/10/17 12:29:50 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
int main(int argc, char **argv)
{
t_simulation sim;
initialize_simulation(&sim, argc, argv);
join_threads(&sim);
cleanup(&sim);
return (0);
}

44
memory.c Executable file
View File

@@ -0,0 +1,44 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* clean.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 11:45:37 by fgras-ca #+# #+# */
/* Updated: 2023/10/17 11:48:26 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
int allocate_memory(t_simulation *sim)
{
sim->forks = ft_calloc(sim->num_philosophers, sizeof(t_fork));
if (!sim->forks)
return (-1);
sim->philos = ft_calloc(sim->num_philosophers, sizeof(t_philo));
if (!sim->philos)
{
free(sim->forks);
return (-1);
}
return (0);
}
void cleanup(t_simulation *sim)
{
int i;
i = 0;
while (i < sim->num_philosophers)
{
pthread_mutex_destroy(&sim->forks[i].mutex_fork);
pthread_mutex_destroy(&sim->philos[i].eating_mutex);
i++;
}
free(sim->philos);
free(sim->forks);
pthread_mutex_destroy(&sim->end_mutex);
pthread_mutex_destroy(&sim->print_mutex);
}

106
monitoring.c Executable file
View File

@@ -0,0 +1,106 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* monitoring.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 12:32:18 by fgras-ca #+# #+# */
/* Updated: 2023/10/23 16:22:19 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
int check_philosopher_death(t_philo *philo)
{
long time_since_last_meal;
pthread_mutex_lock(&philo->eating_mutex);
time_since_last_meal = get_time(philo->sim->start_time)
- philo->last_meal_time;
if (time_since_last_meal <= philo->sim->time_to_die)
{
pthread_mutex_unlock(&philo->eating_mutex);
return (0);
}
pthread_mutex_unlock(&philo->eating_mutex);
pthread_mutex_lock(&philo->sim->end_mutex);
if (!philo->sim->is_philosopher_dead)
{
philo->sim->is_philosopher_dead = 1;
pthread_mutex_unlock(&philo->sim->end_mutex);
print_action(philo, RED"died☠️" RST, 1);
return (1);
}
pthread_mutex_unlock(&philo->sim->end_mutex);
return (0);
}
static int all_philosophers_have_eaten_required_meals(t_simulation *sim)
{
int i;
i = 0;
while (i < sim->num_philosophers)
{
if (sim->philos[i].meals_eaten < sim->max_meals)
{
return (0);
}
i++;
}
return (1);
}
static int handle_all_philosophers_ate(t_philo *philo)
{
if (!philo->sim->simulation_end)
{
philo->sim->simulation_end = 1;
printf(RED"ALL PHILOSOPHERS EAT %d MEALS!!"RST"\n",
philo->sim->max_meals);
print_action(philo, NULL, 1);
return (1);
}
return (0);
}
static int check_max_meals(t_philo *philo)
{
if (philo->sim->max_meals == 0)
{
return (0);
}
pthread_mutex_lock(&philo->sim->end_mutex);
if (all_philosophers_have_eaten_required_meals(philo->sim))
{
pthread_mutex_unlock(&philo->sim->end_mutex);
return (handle_all_philosophers_ate(philo));
}
pthread_mutex_unlock(&philo->sim->end_mutex);
return (0);
}
void *philo_monitor(void *arg)
{
t_philo *philo;
int dead;
int simulation_end;
philo = (t_philo *)arg;
while (1)
{
pthread_mutex_lock(&philo->sim->end_mutex);
dead = philo->sim->is_philosopher_dead;
simulation_end = philo->sim->simulation_end;
pthread_mutex_unlock(&philo->sim->end_mutex);
if (dead || simulation_end)
break ;
if (check_philosopher_death(philo))
return (NULL);
if (check_max_meals(philo))
return (NULL);
}
return (NULL);
}

91
philo.h Executable file
View File

@@ -0,0 +1,91 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* philo.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/12 10:44:03 by fgras-ca #+# #+# */
/* Updated: 2023/10/23 16:29:16 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef PHILO_H
# define PHILO_H
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <sys/time.h>
# include <pthread.h>
# include <limits.h>
# define RST "\033[0;39m"
# define GRAY "\033[0;90m"
# define RED "\033[0;91m"
# define GREEN "\033[0;92m"
# define YELLOW "\033[0;93m"
# define BLUE "\033[0;94m"
# define MAGENTA "\033[0;95m"
# define CYAN "\033[0;96m"
# define WHITE "\033[0;97m"
# define ORANGE "\033[38;5;214m"
typedef struct s_simulation t_simulation;
typedef struct s_fork
{
pthread_mutex_t mutex_fork;
} t_fork;
typedef struct s_philo
{
int id;
int meals_eaten;
int can_eat;
long last_meal_time;
t_fork *left_fork;
t_fork *right_fork;
pthread_t thread;
pthread_t philosopher_monitor;
pthread_mutex_t eating_mutex;
t_simulation *sim;
} t_philo;
typedef struct s_simulation
{
int num_philosophers;
int time_to_die;
int time_to_eat;
int time_to_sleep;
int max_meals;
long start_time;
t_philo *philos;
t_fork *forks;
volatile int is_philosopher_dead;
volatile int simulation_end;
pthread_mutex_t print_mutex;
pthread_mutex_t end_mutex;
} t_simulation;
int initialize_simulation(t_simulation *sim, int argc, char **argv);
int initialize_philosophers(t_simulation *sim);
int ft_atoi(const char *nptr);
int init_threads(t_simulation *sim);
int join_threads(t_simulation *sim);
int args_values(t_simulation *sim, int argc, char **argv);
int initialize_default_values(t_simulation *sim);
int allocate_memory(t_simulation *sim);
long initialize_start_time(void);
long get_time(long start_time);
void *philosopher_life(void *arg);
void cleanup(t_simulation *sim);
void take_forks(t_philo *philo);
void release_forks(t_philo *philo);
void print_action(t_philo *philo, char *action, int death_action);
void eat(t_philo *philo);
void think(t_philo *philo);
void *philo_monitor(void *arg);
void *ft_calloc(size_t nmemb, size_t size);
#endif

38
philos.c Executable file
View File

@@ -0,0 +1,38 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* philos.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 14:31:06 by fgras-ca #+# #+# */
/* Updated: 2023/10/17 15:05:24 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
int initialize_philosophers(t_simulation *sim)
{
int i;
i = 0;
if (allocate_memory(sim) < 0)
return (-1);
while (i < sim->num_philosophers)
{
sim->philos[i].id = i + 1;
pthread_mutex_init(&sim->forks[i].mutex_fork, NULL);
sim->philos[i].left_fork = &sim->forks[i];
sim->philos[i].right_fork = &sim->forks[(i + 1)
% sim->num_philosophers];
sim->philos[i].sim = sim;
sim->philos[i].meals_eaten = 0;
sim->philos[i].can_eat = 0;
sim->philos[i].last_meal_time = get_time(sim->start_time);
pthread_mutex_init(&sim->philos[i].eating_mutex, NULL);
i++;
}
init_threads(sim);
return (0);
}

73
routine.c Executable file
View File

@@ -0,0 +1,73 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* routine.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 15:20:10 by fgras-ca #+# #+# */
/* Updated: 2023/10/23 16:27:02 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
void eat(t_philo *philo)
{
pthread_mutex_lock(&philo->eating_mutex);
if (get_time(philo->sim->start_time)
- philo->last_meal_time > philo->sim->time_to_die)
{
pthread_mutex_unlock(&philo->eating_mutex);
return ;
}
if (!philo->can_eat)
{
pthread_mutex_unlock(&philo->eating_mutex);
return ;
}
philo->last_meal_time = get_time(philo->sim->start_time);
philo->meals_eaten++;
usleep(philo->sim->time_to_eat * 1000);
pthread_mutex_unlock(&philo->eating_mutex);
usleep(300);
}
void philo_sleep(t_philo *philo)
{
philo->can_eat = 0;
usleep(philo->sim->time_to_sleep * 1000);
}
void think(t_philo *philo)
{
philo->can_eat = 0;
}
void *philosopher_life(void *arg)
{
t_philo *philo;
int continue_running;
philo = (t_philo *)arg;
continue_running = 1;
while (continue_running)
{
pthread_mutex_lock(&philo->sim->end_mutex);
continue_running = !philo->sim->is_philosopher_dead
&& !philo->sim->simulation_end;
pthread_mutex_unlock(&philo->sim->end_mutex);
if (!continue_running)
break ;
take_forks(philo);
print_action(philo, GREEN"is eating😋"RST, 0);
eat(philo);
release_forks(philo);
philo->can_eat = 0;
print_action(philo, ORANGE"is sleeping😴"RST, 0);
usleep(philo->sim->time_to_sleep * 1000);
print_action(philo, CYAN"is thinking🤔" RST, 0);
think(philo);
}
return (NULL);
}

72
threads.c Executable file
View File

@@ -0,0 +1,72 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* threads.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/12 10:45:20 by fgras-ca #+# #+# */
/* Updated: 2023/10/23 16:28:10 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
static int create_philosopher_threads(t_simulation *sim)
{
int i;
i = 0;
while (i < sim->num_philosophers)
{
if (i % 2 == 0)
pthread_create(&sim->philos[i].thread, NULL,
philosopher_life, &sim->philos[i]);
else
pthread_create(&sim->philos[i].thread, NULL,
philosopher_life, &sim->philos[i]);
i++;
}
return (1);
}
static int create_monitoring_threads(t_simulation *sim)
{
int i;
i = 0;
while (i < sim->num_philosophers)
{
if (i % 2 == 0)
pthread_create(&sim->philos[i].philosopher_monitor, NULL,
philo_monitor, &sim->philos[i]);
else
pthread_create(&sim->philos[i].philosopher_monitor, NULL,
philo_monitor, &sim->philos[i]);
i++;
}
return (1);
}
int init_threads(t_simulation *sim)
{
if (!create_philosopher_threads(sim))
return (0);
if (!create_monitoring_threads(sim))
return (0);
return (1);
}
int join_threads(t_simulation *sim)
{
int i;
i = 0;
while (i < sim->num_philosophers)
{
pthread_join(sim->philos[i].philosopher_monitor, NULL);
pthread_join(sim->philos[i].thread, NULL);
i++;
}
return (1);
}

29
time.c Executable file
View File

@@ -0,0 +1,29 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* time.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 15:31:00 by fgras-ca #+# #+# */
/* Updated: 2023/10/17 16:20:32 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
long initialize_start_time(void)
{
struct timeval now;
gettimeofday(&now, NULL);
return ((now.tv_sec * 1000) + (now.tv_usec / 1000));
}
long get_time(long start_time)
{
struct timeval now;
gettimeofday(&now, NULL);
return (((now.tv_sec * 1000) + (now.tv_usec / 1000)) - start_time);
}

90
utils.c Executable file
View File

@@ -0,0 +1,90 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* utils.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/17 16:21:02 by fgras-ca #+# #+# */
/* Updated: 2023/10/17 16:27:28 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "philo.h"
static void ft_bzero(void *ptr, size_t len)
{
size_t i;
i = 0;
while (i < len)
{
*(char *)(ptr + i) = 0;
i++;
}
}
void *ft_calloc(size_t nmemb, size_t size)
{
void *ptr;
if (!nmemb || !size)
return (malloc(0));
if ((nmemb * size) / size != nmemb)
return (NULL);
ptr = malloc(size * nmemb);
if (!ptr)
return (0);
ft_bzero(ptr, size * nmemb);
return (ptr);
}
int ft_atoi(const char *nptr)
{
int i;
int sign;
int res;
i = 0;
sign = 1;
res = 0;
while (nptr[i] == 32 || (nptr[i] >= 9 && nptr[i] <= 13))
i++;
if (nptr[i] == '-' || nptr[i] == '+')
{
if (nptr[i] == '-')
sign = - (1);
i++;
}
while (nptr[i] >= 48 && nptr[i] <= 57)
{
res = res * 10 + nptr[i] - 48;
i++;
}
return (res * sign);
}
void print_action(t_philo *philo, char *action, int death_action)
{
t_simulation *sim;
int is_dead;
int all_eat;
sim = philo->sim;
pthread_mutex_lock(&sim->print_mutex);
pthread_mutex_lock(&sim->end_mutex);
is_dead = sim->is_philosopher_dead;
all_eat = sim->simulation_end;
pthread_mutex_unlock(&sim->end_mutex);
if ((is_dead || all_eat) && !death_action)
{
pthread_mutex_unlock(&sim->print_mutex);
return ;
}
if (action)
{
printf("%ld ms"YELLOW" %d %s\n", get_time(sim->start_time),
philo->id, action);
}
pthread_mutex_unlock(&sim->print_mutex);
}