commit d3e7bd98b54bcf42b26a8b29d1944c82d28887ba Author: Ladebeze66 Date: Tue Dec 12 17:37:16 2023 +0100 philosophers diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..ee8eca6 --- /dev/null +++ b/Makefile @@ -0,0 +1,76 @@ +# **************************************************************************** # +# # +# ::: :::::::: # +# Makefile :+: :+: :+: # +# +:+ +:+ +:+ # +# By: fgras-ca +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# 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 diff --git a/en.subject.pdf b/en.subject.pdf new file mode 100644 index 0000000..2ae0b64 --- /dev/null +++ b/en.subject.pdf @@ -0,0 +1,291 @@ + Philosophers + +I never thought philosophy would be so deadly + + Summary: + In this project, you will learn the basics of threading a process. + You will see how to create threads and you will discover mutexes. + + Version: 11 + Contents + +I Introduction 2 + +II Common Instructions 3 + +III Overview 5 + +IV Global rules 6 + +V Mandatory part 8 + +VI Bonus part 9 + +VII Submission and peer-evaluation 10 + + 1 + Chapter I + +Introduction + +Philosophy (from Greek, philosophia, literally "love of wisdom") is the study of general +and fundamental questions about existence, knowledge, values, reason, mind, and lan- +guage. Such questions are often posed as problems to be studied or resolved. The term +was probably coined by Pythagoras (c. 570 – 495 BCE). Philosophical methods include +questioning, critical discussion, rational argument, and systematic presentation. + + Classic philosophical questions include: Is it possible to know anything and to prove +it? What is most real? Philosophers also pose more practical and concrete questions such +as: Is there a best way to live? Is it better to be just or unjust (if one can get away with +it)? Do humans have free will? + + Historically, "philosophy" encompassed any body of knowledge. From the time of An- +cient Greek philosopher Aristotle to the 19th century, "natural philosophy" encompassed +astronomy, medicine, and physics. For example, Newton’s 1687 Mathematical Principles +of Natural Philosophy later became classified as a book of physics. + + In the 19th century, the growth of modern research universities led academic philos- +ophy and other disciplines to professionalize and specialize. In the modern era, some +investigations that were traditionally part of philosophy became separate academic dis- +ciplines, including psychology, sociology, linguistics, and economics. + + Other investigations closely related to art, science, politics, or other pursuits remained +part of philosophy. For example, is beauty objective or subjective? Are there many sci- +entific methods or just one? Is political utopia a hopeful dream or hopeless fantasy? +Major sub-fields of academic philosophy include metaphysics ("concerned with the fun- +damental nature of reality and being"), epistemology (about the "nature and grounds of +knowledge [and]... its limits and validity"), ethics, aesthetics, political philosophy, logic +and philosophy of science. + + 2 + Chapter II + +Common Instructions + + • Your project must be written in C. + + • Your project must be written in accordance with the Norm. If you have bonus + files/functions, they are included in the norm check and you will receive a 0 if there + is a norm error inside. + + • Your functions should not quit unexpectedly (segmentation fault, bus error, double + free, etc) apart from undefined behaviors. If this happens, your project will be + considered non functional and will receive a 0 during the evaluation. + + • All heap allocated memory space must be properly freed when necessary. No leaks + will be tolerated. + + • If the subject requires it, you must submit a Makefile which will compile your + source files to the required output with the flags -Wall, -Wextra and -Werror, use + cc, and your Makefile must not relink. + + • Your Makefile must at least contain the rules $(NAME), all, clean, fclean and + re. + + • To turn in bonuses to your project, you must include a rule bonus to your Makefile, + which will add all the various headers, librairies or functions that are forbidden on + the main part of the project. Bonuses must be in a different file _bonus.{c/h} if + the subject does not specify anything else. Mandatory and bonus part evaluation + is done separately. + + • If your project allows you to use your libft, you must copy its sources and its + associated Makefile in a libft folder with its associated Makefile. Your project’s + Makefile must compile the library by using its Makefile, then compile the project. + + • We encourage you to create test programs for your project even though this work + won’t have to be submitted and won’t be graded. It will give you a chance + to easily test your work and your peers’ work. You will find those tests especially + useful during your defence. Indeed, during defence, you are free to use your tests + and/or the tests of the peer you are evaluating. + + • Submit your work to your assigned git repository. Only the work in the git reposi- + tory will be graded. If Deepthought is assigned to grade your work, it will be done + + 3 + Philosophers I never thought philosophy would be so deadly + +after your peer-evaluations. If an error happens in any section of your work during +Deepthought’s grading, the evaluation will stop. + + 4 + Chapter III + +Overview + +Here are the things you need to know if you want to succeed this assignment: + • One or more philosophers sit at a round table. + There is a large bowl of spaghetti in the middle of the table. + • The philosophers alternatively eat, think, or sleep. + While they are eating, they are not thinking nor sleeping; + while thinking, they are not eating nor sleeping; + and, of course, while sleeping, they are not eating nor thinking. + • There are also forks on the table. There are as many forks as philosophers. + • Because serving and eating spaghetti with only one fork is very inconvenient, a + philosopher takes their right and their left forks to eat, one in each hand. + • When a philosopher has finished eating, they put their forks back on the table and + start sleeping. Once awake, they start thinking again. The simulation stops when + a philosopher dies of starvation. + • Every philosopher needs to eat and should never starve. + • Philosophers don’t speak with each other. + • Philosophers don’t know if another philosopher is about to die. + • No need to say that philosophers should avoid dying! + + 5 + Chapter IV + +Global rules + +You have to write a program for the mandatory part and another one for the bonus part +(if you decide to do the bonus part). They both have to comply with the following rules: + + • Global variables are forbidden! + • Your(s) program(s) should take the following arguments: + + number_of_philosophers time_to_die time_to_eat time_to_sleep + [number_of_times_each_philosopher_must_eat] + + ◦ number_of_philosophers: The number of philosophers and also the number + of forks. + + ◦ time_to_die (in milliseconds): If a philosopher didn’t start eating time_to_die + milliseconds since the beginning of their last meal or the beginning of the sim- + ulation, they die. + + ◦ time_to_eat (in milliseconds): The time it takes for a philosopher to eat. + During that time, they will need to hold two forks. + + ◦ time_to_sleep (in milliseconds): The time a philosopher will spend sleeping. + ◦ number_of_times_each_philosopher_must_eat (optional argument): If all + + philosophers have eaten at least number_of_times_each_philosopher_must_eat + times, the simulation stops. If not specified, the simulation stops when a + philosopher dies. + • Each philosopher has a number ranging from 1 to number_of_philosophers. + • Philosopher number 1 sits next to philosopher number number_of_philosophers. + Any other philosopher number N sits between philosopher number N - 1 and philoso- + pher number N + 1. + + 6 + Philosophers I never thought philosophy would be so deadly + +About the logs of your program: + +• Any state change of a philosopher must be formatted as follows: + + ◦ timestamp_in_ms X has taken a fork + ◦ timestamp_in_ms X is eating + ◦ timestamp_in_ms X is sleeping + ◦ timestamp_in_ms X is thinking + ◦ timestamp_in_ms X died + + Replace timestamp_in_ms with the current timestamp in milliseconds + and X with the philosopher number. +• A displayed state message should not be mixed up with another message. +• A message announcing a philosopher died should be displayed no more than 10 ms + after the actual death of the philosopher. +• Again, philosophers should avoid dying! + + Your program must not have any data races. + + 7 + Chapter V +Mandatory part + +Program name philo +Turn in files Makefile, *.h, *.c, in directory philo/ +Makefile NAME, all, clean, fclean, re +Arguments number_of_philosophers time_to_die time_to_eat + time_to_sleep +External functs. [number_of_times_each_philosopher_must_eat] + memset, printf, malloc, free, write, +Libft authorized usleep, gettimeofday, pthread_create, +Description pthread_detach, pthread_join, pthread_mutex_init, + pthread_mutex_destroy, pthread_mutex_lock, + pthread_mutex_unlock + No + Philosophers with threads and mutexes + +The specific rules for the mandatory part are: + +• Each philosopher should be a thread. + +• There is one fork between each pair of philosophers. Therefore, if there are several + philosophers, each philosopher has a fork on their left side and a fork on their right + side. If there is only one philosopher, there should be only one fork on the table. + +• To prevent philosophers from duplicating forks, you should protect the forks state + with a mutex for each of them. + + 8 + Chapter VI +Bonus part + +Program name philo_bonus +Turn in files Makefile, *.h, *.c, in directory philo_bonus/ +Makefile NAME, all, clean, fclean, re +Arguments number_of_philosophers time_to_die time_to_eat + time_to_sleep +External functs. [number_of_times_each_philosopher_must_eat] + memset, printf, malloc, free, write, fork, kill, +Libft authorized exit, pthread_create, pthread_detach, pthread_join, +Description usleep, gettimeofday, waitpid, sem_open, sem_close, + sem_post, sem_wait, sem_unlink + No + Philosophers with processes and semaphores + + The program of the bonus part takes the same arguments as the mandatory program. +It has to comply with the requirements of the Global rules chapter. + +The specific rules for the bonus part are: + +• All the forks are put in the middle of the table. + +• They have no states in memory but the number of available forks is represented by + a semaphore. + +• Each philosopher should be a process. But the main process should not be a + philosopher. + +The bonus part will only be assessed if the mandatory part is +PERFECT. Perfect means the mandatory part has been integrally done +and works without malfunctioning. If you have not passed ALL the +mandatory requirements, your bonus part will not be evaluated at all. + + 9 + Chapter VII + +Submission and peer-evaluation + +Turn in your assignment in your Git repository as usual. Only the work inside your repos- +itory will be evaluated during the defense. Don’t hesitate to double check the names of +your files to ensure they are correct. + + Mandatory part directory: philo/ + Bonus part directory: philo_bonus/ + + V L ( Lp aW 8 + + ) * q fx 2 u L 5 kt 6 ::/ . + +? p x >g 0 Jb n R V + + 7 vo + + v c pt g j + + S 4 H . + + I 6 <) + + A2 5 ) E ? d + + B f - Z ‘ + + *v + + , ;I I + + sC: + + 10 + diff --git a/forks.c b/forks.c new file mode 100755 index 0000000..309a97d --- /dev/null +++ b/forks.c @@ -0,0 +1,69 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* forks.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/initialize.c b/initialize.c new file mode 100755 index 0000000..6c9227e --- /dev/null +++ b/initialize.c @@ -0,0 +1,60 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* initialize.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/main.c b/main.c new file mode 100755 index 0000000..f5c69e6 --- /dev/null +++ b/main.c @@ -0,0 +1,23 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/memory.c b/memory.c new file mode 100755 index 0000000..db7dcb8 --- /dev/null +++ b/memory.c @@ -0,0 +1,44 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* clean.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/monitoring.c b/monitoring.c new file mode 100755 index 0000000..30d272c --- /dev/null +++ b/monitoring.c @@ -0,0 +1,106 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* monitoring.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/philo.h b/philo.h new file mode 100755 index 0000000..6b07267 --- /dev/null +++ b/philo.h @@ -0,0 +1,91 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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 +# include +# include +# include +# include +# include + +# 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 diff --git a/philos.c b/philos.c new file mode 100755 index 0000000..7bac5f6 --- /dev/null +++ b/philos.c @@ -0,0 +1,38 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philos.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/routine.c b/routine.c new file mode 100755 index 0000000..3caecca --- /dev/null +++ b/routine.c @@ -0,0 +1,73 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* routine.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/threads.c b/threads.c new file mode 100755 index 0000000..07be359 --- /dev/null +++ b/threads.c @@ -0,0 +1,72 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* threads.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/time.c b/time.c new file mode 100755 index 0000000..e09754d --- /dev/null +++ b/time.c @@ -0,0 +1,29 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* time.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +} diff --git a/utils.c b/utils.c new file mode 100755 index 0000000..432d09e --- /dev/null +++ b/utils.c @@ -0,0 +1,90 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* 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); +}