diff --git a/README.md b/README.md index e56ed74..9c69dc7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,30 @@ # Philosophers -42 school project \ No newline at end of file +42 school project + + + +PHILOSOPHERS BONUS +=== + +## Subject : + + +## Docs : +[Semaphores](https://sites.uclouvain.be/SyllabusC/notes/Theorie/Threads/coordination.html) + + +## Structure : + +Main : + +- parsing() -> + - create table and *philos + - setup parameters +- create sticks semaphore +- init_philos() -> + - create array of childs pids + - for each philo, create a fork() : + - philo_life() -> + - +- loop diff --git a/philo/Makefile b/philo/Makefile new file mode 100644 index 0000000..990ed2d --- /dev/null +++ b/philo/Makefile @@ -0,0 +1,26 @@ +NAME = philosophers + +SRCS = philo_threads.c philo_launcher.c philo_utils.c philo_init.c +OBJS = ${SRCS:.c=.o} + +CC = gcc +CFLAGS = -Werror -Wextra -Wall -g -fsanitize=thread -D_REENTRANT +RM = rm -rf + +.c.o: + $(CC) $(CFLAGS) -c $< -o $(<:.c=.o) + +all: $(NAME) + +$(NAME): $(OBJS) + ${CC} ${CFLAGS} -lpthread ${OBJS} -o ${NAME} + +clean: + ${RM} ${OBJS} + +fclean: clean + ${RM} ${NAME} + +re: fclean all + +.PHONY: all clean fclean re diff --git a/philo/philo_init.c b/philo/philo_init.c new file mode 100644 index 0000000..4dda75e --- /dev/null +++ b/philo/philo_init.c @@ -0,0 +1,62 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo_init.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: narnaud +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/04/11 10:33:01 by narnaud #+# #+# */ +/* Updated: 2022/04/11 10:35:12 by narnaud ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philosophers.h" + +t_param *init_param(char **argv) +{ + t_param *ret; + + ret = malloc(sizeof(t_param)); + ret->philo_amount = mini_atoi(argv[0]); + ret->die_time = mini_atoi(argv[1]); + ret->eat_duration = mini_atoi(argv[2]); + ret->sleep_duration = mini_atoi(argv[3]); + if (argv[4]) + ret->eat_amount = mini_atoi(argv[4]); + else + ret->eat_amount = 2147483647; + return (ret); +} + +t_room *init_room(char **argv) +{ + t_room *room; + struct timeval time; + static int i = 0; + + gettimeofday(&time, NULL); + room = malloc(sizeof(t_room)); + room->param = init_param(argv); + room->safe = malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(room->safe, NULL); + room->philos = \ + (t_philo **)malloc(room->param->philo_amount * sizeof(t_philo *)); + room->running = 1; + room->start_time = time.tv_sec * 1000 + time.tv_usec / 1000; + room->time = 0; + room->i = 0; + while (i < room->param->philo_amount) + { + room->philos[i] = (t_philo *)malloc(sizeof(t_philo)); + room->philos[i]->fork = malloc(sizeof(pthread_mutex_t)); + room->philos[i]->safe = malloc(sizeof(pthread_mutex_t)); + room->philos[i]->thd = malloc(sizeof(pthread_t)); + room->philos[i]->eat_time = room->time; + room->philos[i]->eat_amount = 0; + room->philos[i]->i = i; + pthread_mutex_init(room->philos[i]->fork, NULL); + pthread_mutex_init(room->philos[i++]->safe, NULL); + } + return (room); +} + diff --git a/philo/philo_launcher.c b/philo/philo_launcher.c new file mode 100644 index 0000000..7c9ea4a --- /dev/null +++ b/philo/philo_launcher.c @@ -0,0 +1,77 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo_launcher.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: narnaud +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/24 15:44:04 by narnaud #+# #+# */ +/* Updated: 2022/04/11 14:55:43 by narnaud ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philosophers.h" + +int waiter(t_room *room); + +int main(int argc, char **argv) +{ + t_room *room; + + if (argc < 5 || argc > 6) + return (1); + room = init_room(argv + 1); + pthread_create(&room->clock_thd, NULL, room_clock, (void *)room); + while (room->i >= 0) + { + pthread_mutex_lock(room->safe); + if (room->i >= room->param->philo_amount) + room->i -= 1 + (room->param->philo_amount % 2) * 2; + pthread_create(room->philos[room->i]->thd, NULL, \ + philos_life, (void *)room); + pthread_detach(*room->philos[room->i]->thd); + pthread_mutex_unlock(room->safe); + usleep(CLOCK_ONE); + pthread_mutex_lock(room->safe); + if ((room->i % 2) == 0) + room->i += 2; + else if ((room->i % 2) == 1) + room->i -= 2; + pthread_mutex_unlock(room->safe); + } + while (!waiter(room)) + usleep(CLOCK_TWO); + return (clean_memory(room)); +} + +int waiter(t_room *room) +{ + t_param *param; + int i; + int starvest; + + pthread_mutex_lock(room->safe); + i = 0; + param = room->param; + starvest = param->eat_amount; + while (i < param->philo_amount) + { + pthread_mutex_lock(room->philos[i]->safe); + if (room->philos[i]->eat_time + param->die_time < room->time) + { + safe_print("%ld %d died\n", room, i); + room->running = 0; + pthread_mutex_unlock(room->philos[i]->safe); + pthread_mutex_unlock(room->safe); + return (1); + } + if (room->philos[i]->eat_amount < starvest) + starvest = room->philos[i]->eat_amount; + pthread_mutex_unlock(room->philos[i]->safe); + i++; + } + if (starvest == param->eat_amount) + room->running = 0; + pthread_mutex_unlock(room->safe); + return (!room->running); +} diff --git a/philo/philo_threads.c b/philo/philo_threads.c new file mode 100644 index 0000000..bbed929 --- /dev/null +++ b/philo/philo_threads.c @@ -0,0 +1,84 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo_threads.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: narnaud +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/26 07:43:48 by narnaud #+# #+# */ +/* Updated: 2022/04/11 14:52:22 by narnaud ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philosophers.h" + +void *philos_life(void *r) +{ + t_room *room; + t_param *param; + t_philo *philo; + int id; + int id_p; + + room = (t_room *)r; + param = room->param; + pthread_mutex_lock(room->safe); + id = room->i; + philo = room->philos[id]; + philo->eat_time = room->time; + id_p = (id + 1) % param->philo_amount; + pthread_mutex_unlock(room->safe); + while (room->running) + { + pthread_mutex_lock(philo->fork); + safe_print("%ld %d has taken a fork\n", room, id); + pthread_mutex_lock(room->philos[id_p]->fork); + safe_print("%ld %d has taken a fork\n", room, id); + safe_print("%ld %d is eating\n", room, id); + pthread_mutex_lock(philo->safe); + philo->eat_time = room->time; + pthread_mutex_unlock(philo->safe); + if (check_end(room)) + { + pthread_mutex_unlock(philo->fork); + pthread_mutex_unlock(room->philos[id_p]->fork); + return (NULL); + } + usleep(param->eat_duration * 1000); + pthread_mutex_unlock(philo->fork); + pthread_mutex_unlock(room->philos[id_p]->fork); + if (check_end(room)) + return (NULL); + safe_print("%ld %d is sleeping\n", room, id); + pthread_mutex_lock(philo->safe); + philo->eat_amount++; + pthread_mutex_unlock(philo->safe); + usleep(param->sleep_duration * 1000); + if (check_end(room)) + return (NULL); + safe_print("%ld %d is thinking\n", room, id); + } + return (NULL); +} + +void *room_clock(void *r) +{ + t_room *room; + struct timeval time; + + room = (t_room *)r; + while (1) + { + gettimeofday(&time, NULL); + pthread_mutex_lock(room->safe); + room->time = time.tv_sec * 1000 + time.tv_usec / 1000 - room->start_time; + if (!room->running) + { + pthread_mutex_unlock(room->safe); + return(NULL); + } + pthread_mutex_unlock(room->safe); + usleep(CLOCK_TWO); + } + return (NULL); +} diff --git a/philo/philo_utils.c b/philo/philo_utils.c new file mode 100644 index 0000000..549780d --- /dev/null +++ b/philo/philo_utils.c @@ -0,0 +1,71 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: narnaud +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/04/11 10:29:50 by narnaud #+# #+# */ +/* Updated: 2022/04/11 14:50:59 by narnaud ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philosophers.h" + + +int mini_atoi(char *nbr) +{ + int ret; + + ret = 0; + while (*nbr >= '0' && *nbr <= '9') + { + ret = (*nbr - '0') + (10 * ret); + nbr++; + } +return (ret); +} + +void safe_print(char *str, t_room *room, int id) +{ + pthread_mutex_lock(room->safe); + printf(str, room->time, id); + pthread_mutex_unlock(room->safe); +} + +int check_end(t_room *room) +{ + int ret; + + ret = 0; + pthread_mutex_lock(room->safe); + if (!room->running) + ret = 1; + pthread_mutex_unlock(room->safe); + return (ret); +} +int clean_memory(t_room *room) +{ + t_param *param; + int i; + + i = 0; + param = room->param; + while (i < param->philo_amount) + { + pthread_mutex_destroy(room->philos[i]->safe); + pthread_mutex_destroy(room->philos[i]->fork); + free(room->philos[i]->safe); + free(room->philos[i]->fork); + free(room->philos[i]->thd); + free(room->philos[i]); + i++; + } + pthread_mutex_destroy(room->safe); + free(room->safe); + free(room->philos); + free(room->param); + free(room); + return (0); +} + diff --git a/philo/philosophers.h b/philo/philosophers.h new file mode 100644 index 0000000..a014c4c --- /dev/null +++ b/philo/philosophers.h @@ -0,0 +1,70 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philosophers.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: narnaud +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/24 15:44:06 by narnaud #+# #+# */ +/* Updated: 2022/05/16 14:09:56 by narnaud ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef PHILOSOPHERS_H +# define PHILOSOPHERS_H +# define CLOCK_ONE 500 +# define CLOCK_TWO 1000 + +# include +# include +# include +# include +# include +# include + +typedef struct s_param +{ + int philo_amount; + int die_time; + int eat_duration; + int sleep_duration; + int eat_amount; +} t_param; + +typedef struct s_philo +{ + pthread_mutex_t *fork; + pthread_mutex_t *safe; + pthread_t *thd; + unsigned long eat_time; + int eat_amount; + int i; +} t_philo; + +typedef struct s_room +{ + t_param *param; + t_philo **philos; + pthread_mutex_t *safe; + pthread_t clock_thd; + int running; + unsigned long start_time; + unsigned long time; + int i; +} t_room; + +//philo_threads.c +void *philos_life(void *r); +void *room_clock(void *r); + +//philo_init.c +t_param *init_param(char **argv); +t_room *init_room(char **argv); + +//philo_utils.c +int mini_atoi(char *nbr); +void safe_print(char *str, t_room *room, int id); +int clean_memory(t_room *room); +int check_end(t_room *room); + +#endif diff --git a/philo_bonus/philo.c b/philo_bonus/philo.c new file mode 100644 index 0000000..adbc876 --- /dev/null +++ b/philo_bonus/philo.c @@ -0,0 +1,102 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: narnaud +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/05/16 14:03:42 by narnaud #+# #+# */ +/* Updated: 2022/05/16 14:03:47 by narnaud ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philosophers.h" + +void *check_halt(void * p) +{ + size_t time; + t_philo *philo; + + philo = p; + while (1) + { + usleep(1000); + time = gettime(); + philo->table->time = time; + if (time - philo->last_meal_time > philo->table->time_to_die) + { + printf("%lu %d died\n", time, philo->id); + exit(EXIT_SUCCESS); + } + } +} + +void philo_life(t_philo *philo) +{ + t_table *table; + + table = philo->table; + while (1) + { + sem_wait(table->sptr); + printf("%lu %d has taken a fork\n", table->time, philo->id); + sem_wait(table->sptr); + printf("%lu %d has taken a fork\n", table->time, philo->id); + philo->last_meal_time = table->time; + printf("%lu %d is eating\n", table->time, philo->id); + usleep(table->eating_time * 1000); + sem_post(table->sptr); + sem_post(table->sptr); + printf("%lu %d is sleeping\n", table->time, philo->id); + usleep(table->sleeping_time * 1000); + printf("%lu %d is thinking\n", table->time, philo->id); + } +} + +void init_philos(t_table *table) +{ + size_t i; + pthread_t checks; + + table->pid = malloc(sizeof(pid_t) * table->nb_of_philos); + memset(table->pid, 0, sizeof(pid_t) * table->nb_of_philos); + i = 0; + while (i < table->nb_of_philos) + { + table->pid[i] = fork(); + table->philos[i].table = table; + table->philos[i].id = i; + if (!table->pid[i]) + { + pthread_create(&checks, NULL, check_halt, table->philos + i); + philo_life(table->philos + i); + } + usleep(500); + i++; + } +} + +int main(int argc, char **argv) +{ + static t_table *table; + static size_t i = 0; + int status; + + sem_unlink("/chopsticks"); + sem_unlink("/death"); + if (argc < 5 || argc > 6) + return (1); + table = parsing(argv + 1); + table->sptr = sem_open("/chopsticks", O_CREAT, 0664, table->nb_of_philos); + table->death = sem_open("/death", O_CREAT, 0664, 1); + init_philos(table); + waitpid(-1, &status, 0); + while (i < table->nb_of_philos) + { + kill(table->pid[i], SIGINT); + i++; + } + sem_unlink("/chopsticks"); + sem_unlink("/deaths"); + return(0); +} diff --git a/philo_bonus/philo_utils.c b/philo_bonus/philo_utils.c new file mode 100644 index 0000000..d765be4 --- /dev/null +++ b/philo_bonus/philo_utils.c @@ -0,0 +1,60 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: narnaud +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/05/16 14:04:06 by narnaud #+# #+# */ +/* Updated: 2022/05/16 14:04:11 by narnaud ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philosophers.h" + +static int mini_atoi(char *nbr) +{ + int ret; + + ret = 0; + while (*nbr >= '0' && *nbr <= '9') + { + ret = (*nbr - '0') + (10 * ret); + nbr++; + } + return (ret); +} + +t_table *parsing(char **argv) +{ + t_table *table; + + table = malloc(sizeof(t_table)); + memset(table, 0, sizeof(t_table)); + table->nb_of_philos = mini_atoi(argv[0]); + table->philos = malloc(sizeof(t_philo) * table->nb_of_philos); + memset(table->philos, 0, sizeof(t_philo) * table->nb_of_philos); + table->time_to_die = mini_atoi(argv[1]); + table->eating_time = mini_atoi(argv[2]); + table->sleeping_time = mini_atoi(argv[3]); + table->time = gettime(); + if (argv[4]) + table->nb_of_meal = mini_atoi(argv[4]); + else + table->nb_of_meal = 2147483647; + return (table); +} + +size_t gettime(void) +{ + static struct timeval time = {0,0}; + struct timeval actualtime; + size_t ret; + + if(time.tv_sec == 0 && time.tv_usec == 0) + gettimeofday(&time, NULL); + gettimeofday(&actualtime, NULL); + ret = (size_t)((actualtime.tv_sec * 1000 + actualtime.tv_usec / 1000)\ + - (time.tv_sec * 1000 + time.tv_usec / 1000)); + return (ret); +} diff --git a/philo_bonus/philosophers.h b/philo_bonus/philosophers.h new file mode 100644 index 0000000..5a9a840 --- /dev/null +++ b/philo_bonus/philosophers.h @@ -0,0 +1,71 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philosophers.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: narnaud +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/05/16 14:03:01 by narnaud #+# #+# */ +/* Updated: 2022/05/16 14:03:20 by narnaud ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef PHILOSOPHERS_H +# define PHILOSOPHERS_H + +/* + +• Chaque philosophe doit être représenté par un thread. +• Toutes les fourchettes sont au centre de la table. +• Elles n’ont pas d’état spécifique en mémoire, mais le nombre de fourchettes +disponibles est représenté par un sémaphore. • Chaque philosophe est représenté +par un processus différent. Cependant, le processus principal ne doit pas être +un philosophe. + +*/ + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +typedef struct s_table t_table; + +typedef struct s_philo +{ + int id; + size_t meals_done; + size_t last_meal_time; + t_table *table; +} t_philo; + +typedef struct s_table +{ + size_t nb_of_philos; + size_t time_to_die; + size_t eating_time; + size_t sleeping_time; + size_t nb_of_meal; + int i; + sem_t *sptr; + sem_t *death; + t_philo *philos; + size_t time; + size_t start_time; + int *pid; +} t_table; + +/***************************/ + +t_table *parsing(char **argv); +size_t gettime(void); + +#endif