diff --git a/Makefile b/Makefile index b970f35..10dd4c3 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ NAME = philo CC = clang -CFLAGS = -Wall -Wextra $(INCLUDES) -g # add -Werror, del -g +CFLAGS = -Wall -Wextra -Werror $(INCLUDES) -g3 # del g3 VPATH = $(DIR_SRCS) DIR_SRCS = srcs @@ -10,7 +10,10 @@ DIR_SRCS = srcs INCLUDES = -I$(HEADERS_D) -I$(LIBFT_D) HEADERS_D = ./headers -HEADERS = philo.h +HEADERS = philo.h \ + philo_struct.h \ + philo_proto.h \ + philo_macro.h LIBS = -L $(LIBFT_D) -lft \ -lpthread @@ -18,7 +21,9 @@ LIBS = -L $(LIBFT_D) -lft \ LIBFT_D = ./libft LIBFT = $(LIBFT_D)/libft.a -SRCS = main.c +SRCS = main.c \ + init.c \ + exec.c DIR_OBJS = builds OBJS = $(SRCS:%.c=$(DIR_OBJS)/%.o) diff --git a/README.md b/README.md index 334ef4c..609b773 100644 --- a/README.md +++ b/README.md @@ -4,43 +4,53 @@ options : - t_die -> time_to_die - t_eat -> time_to_eat - t_slp -> time_to_sleep -- n_est -> [number_of_times_each_philosopher_must_eat] +- n_eat -> [number_of_times_each_philosopher_must_eat] ``` -thread : -- thread are light-weight-process (LWP) that happens inside a process +**thread :** + +- parts of a process that performs code simultaneously +- thread are light-weight-process (LWP) that happens inside a process (observe with command `ps -eLf`) - a process can be single-threaded or multi-threaded -- different process have a unique PID with a unique LWP, different thread in the same process have the same PID and a different LWP +- different process have a different PID and different LWP, different thread in the same process have the same PID and different LWP - thread vs process : - process : + + *process :* + - process is isolated, it doesn't share memory with any other process - - process can have states : new, ready, running, waiting, terminated, suspended - process is less efficient in communication, it takes more times to create or terminate or switch - process speed is not impacted by speed of other process (untill it reach the limit of cpu) - - process are created with fork() and execve() (to duplicate a process in a child process, or replacing an existing process) - thread : - - thread are not isolated - - thread can have states : running, ready, blocked + + *thread :* + + - thread are not isolated, they share memory with the other threads - thread is more efficient in communication, it takes less times to create or terminate or switch - thread can become slow if the process does many concurrent tasks + - ressources : - https://www.baeldung.com/linux/process-vs-thread +**mutex :** -external function : +- mutual exclusion +- to prevent a part of the code to be performed simultaneously by threads +- the section of code wraped by a mutex can be access by only one thread at a time +- the section starts by unlocking a mutex, and end by locking it -memset : fill memory with a constant byte -printf : format and print data -malloc : allocate dynamic memory -free : free dynamic memory -write : write to a file descriptor -usleep : suspend execution for microseconds intervals -gettimeofday : get time -pthread_create : create a new thread -pthread_detach : -pthread_join -pthread_mutex_init -pthread_mutex_destroy -pthread_mutex_lock -pthread_mutex_unlock +**external function :** + +- `memset` : fill memory with a constant byte +- `printf` : format and print data +- `malloc` : allocate dynamic memory +- `free` : free dynamic memory +- `write` : write to a file descriptor +- `usleep` : suspend execution for microseconds intervals +- `gettimeofday`: get time +- `pthread_create` : create a new thread +- `pthread_join` : wait for a thread to finish, +- `pthread_detach` : when a thread is detached it cannot be join, you cannot wait for it to teminate, it will release its ressources on its own when it has finish +- `pthread_mutex_init` : initialize a mutex +- `pthread_mutex_destroy`: destroy a mutex +- `pthread_mutex_unlock` : unlock a mutex +- `pthread_mutex_lock` : lock a mutex diff --git a/headers/philo.h b/headers/philo.h index e052c10..f2d131d 100644 --- a/headers/philo.h +++ b/headers/philo.h @@ -7,10 +7,10 @@ # include # include # include +# include -typedef struct s_philo -{ - char *str; -} t_philo; +# include "philo_struct.h" +# include "philo_proto.h" +# include "philo_macro.h" #endif diff --git a/headers/philo_macro.h b/headers/philo_macro.h new file mode 100644 index 0000000..0147b5b --- /dev/null +++ b/headers/philo_macro.h @@ -0,0 +1,24 @@ +#ifndef PHILO_MACRO_H +# define PHILO_MACRO_H + +# define GRAY "\e[0;30m" +# define RED "\e[0;31m" +# define GREEN "\e[0;32m" +# define YELLOW "\e[0;33m" +# define BLUE "\e[0;34m" +# define PURPLE "\e[0;35m" +# define CYAN "\e[0;36m" +# define WHITE "\e[0;37m" + +# define B_GRAY "\e[1;30m" +# define B_RED "\e[1;31m" +# define B_GREEN "\e[1;32m" +# define B_YELLOW "\e[1;33m" +# define B_BLUE "\e[1;34m" +# define B_PURPLE "\e[1;35m" +# define B_CYAN "\e[1;36m" +# define B_WHITE "\e[1;37m" + +# define RESET "\e[0m" + +#endif diff --git a/headers/philo_proto.h b/headers/philo_proto.h new file mode 100644 index 0000000..ca44930 --- /dev/null +++ b/headers/philo_proto.h @@ -0,0 +1,11 @@ +#ifndef PHILO_PROTO_H +# define PHILO_PROTO_H + +// init.c +t_philo *init(int ac, char **av, pthread_t **id); + +// exec.c +void *philo_exec(void *arg); + +#endif + diff --git a/headers/philo_struct.h b/headers/philo_struct.h new file mode 100644 index 0000000..71b1421 --- /dev/null +++ b/headers/philo_struct.h @@ -0,0 +1,29 @@ +#ifndef PHILO_STRUCT_H +# define PHILO_STRUCT_H + +typedef pthread_mutex_t t_mtx; + +typedef struct s_params +{ + int n_phi; // number_of_philosophers + int t_die; // time_to_die + int t_eat; // time_to_eat + int t_slp; // time_to_sleep + int n_eat; // [number_of_times_each_philosopher_must_eat] +} t_params; + +typedef struct s_philo +{ + t_params *params; + int p_nbr; + t_mtx m_fork; + t_mtx *m_print; + long int t_start_s; + long int t_start_u; + long int t_last_meal_s; + long int t_last_meal_u; + struct s_philo *prev; + struct s_philo *next; +} t_philo; + +#endif diff --git a/philosopher.pdf b/philosopher.pdf new file mode 100644 index 0000000..fff8b93 Binary files /dev/null and b/philosopher.pdf differ diff --git a/srcs/exec.c b/srcs/exec.c new file mode 100644 index 0000000..8b5da1c --- /dev/null +++ b/srcs/exec.c @@ -0,0 +1,82 @@ +#include "philo.h" + +void print_message(t_philo *philo, char *msg) +{ + long int time_stamp; + struct timeval stime; + char *color; + + gettimeofday(&stime, NULL); + time_stamp = (stime.tv_sec - philo->t_start_s) * 1000; + time_stamp += (stime.tv_usec - philo->t_start_u) / 1000; + color = WHITE; + if (ft_strnstr(msg, "eating", ft_strlen(msg))) + color = B_YELLOW; + if (ft_strnstr(msg, "sleeping", ft_strlen(msg))) + color = B_BLUE; + if (ft_strnstr(msg, "thinking", ft_strlen(msg))) + color = B_GREEN; + pthread_mutex_lock(philo->m_print); + ft_printf("%s%i %i %s%s\n", color, time_stamp, philo->p_nbr, msg, RESET); + pthread_mutex_unlock(philo->m_print); +} + +// long int t_start_s; +// long int t_start_u; +// long int t_last_meal_s; +// long int t_last_meal_u; +void init_time(t_philo *philo) +{ + struct timeval stime; + + gettimeofday(&stime, NULL); + philo->t_start_s = stime.tv_sec; + philo->t_start_u = stime.tv_usec; +} + +void update_time(t_philo *philo) +{ + struct timeval stime; + + gettimeofday(&stime, NULL); + philo->t_last_meal_s = stime.tv_sec; + philo->t_last_meal_u = stime.tv_usec; +} + +void take_forks(t_philo *philo) +{ + pthread_mutex_lock(&(philo->m_fork)); + print_message(philo, "has taken a fork"); + pthread_mutex_lock(&(philo->next->m_fork)); + print_message(philo, "has taken a fork"); + + print_message(philo, "is eating"); + usleep(philo->params->t_eat * 1000); + + pthread_mutex_unlock(&(philo->next->m_fork)); + pthread_mutex_unlock(&(philo->m_fork)); +} + +// int n_phi; // number_of_philosophers +// int t_die; // time_to_die +// int t_eat; // time_to_eat +// int t_slp; // time_to_sleep +// int n_eat; // [number_of_times_each_philosopher_must_eat] +void *philo_exec(void *arg) +{ + t_philo *philo; + + philo = (t_philo*)arg; + init_time(philo); + if (philo->p_nbr % 2 == 0) + usleep(10 * 1000); + while (1) + { + take_forks(philo); + + print_message(philo, "is sleeping"); + usleep(philo->params->t_slp * 1000); + print_message(philo, "is thinking"); + } + return (NULL); +} diff --git a/srcs/init.c b/srcs/init.c new file mode 100644 index 0000000..48dee44 --- /dev/null +++ b/srcs/init.c @@ -0,0 +1,81 @@ +#include "philo.h" + +t_philo *lst_add_philo(t_philo *philo, t_params *params, t_mtx *m_print, int i) +{ + t_philo *new; + + new = malloc(sizeof(t_philo) * 1); + if (new == NULL) + return (NULL); + new->params = params; + new->p_nbr = i + 1; + if (pthread_mutex_init(&(new->m_fork), NULL) != 0) + return (NULL); + new->m_print = m_print; + if (philo) + philo->next = new; + new->prev = philo; + return (new); +} + +// looping chained list +t_philo *init_chain_philo(t_params *params, t_mtx *m_print) +{ + t_philo *end; + t_philo *philo; + int i; + + i = 0; + philo = NULL; + while (i < params->n_phi) + { + philo = lst_add_philo(philo, params, m_print, i); + i++; + } + end = philo; + while (philo->prev != NULL) + philo = philo->prev; + philo->prev = end; + end->next = philo; + return (philo); +} + +t_params *init_params(int ac, char **av) +{ + t_params *params; + + if (ac == 5 || ac == 6) + { + params = malloc(sizeof(t_params)); + params->n_phi = ft_atoi(av[1]); + params->t_die = ft_atoi(av[2]); + params->t_eat = ft_atoi(av[3]); + params->t_slp = ft_atoi(av[4]); + if (ac == 6) + params->n_eat = ft_atoi(av[5]); + } + else + return (NULL); + return (params); +} + +t_philo *init(int ac, char **av, pthread_t **id) +{ + t_philo *philo; + t_params *params; + t_mtx *m_print; + + params = init_params(ac, av); + if (params == NULL) + return (NULL); + *id = malloc(sizeof(pthread_t) * params->n_phi); + if (*id == NULL) + return (NULL); + m_print = malloc(sizeof(t_mtx)); + if (pthread_mutex_init(m_print, NULL) != 0) + return (NULL); + philo = init_chain_philo(params, m_print); + if (philo == NULL) + return (NULL); + return (philo); +} diff --git a/srcs/main.c b/srcs/main.c index f5fc7e1..a0ae8df 100644 --- a/srcs/main.c +++ b/srcs/main.c @@ -1,27 +1,36 @@ #include "philo.h" -void *philo_exec(void *arg) +void launch_threads(t_philo *philo, pthread_t *id, int n) { - t_philo *philo; + int i; - philo = (t_philo*)arg; - while (1) - write(1, philo->str, ft_strlen(philo->str)); -} - -int main(void) -{ - pthread_t id; - int ret; - t_philo *philo; - - philo = malloc(sizeof(philo)); - philo->str = "i'm philosopher\n"; - ret = pthread_create(&id, NULL, &philo_exec, philo); - if (ret == 0) + i = 0; + while (i < n) { - while (1) - write(1, "main function\n", 14); + pthread_create(&id[i], NULL, &philo_exec, philo); + philo = philo->next; + i++; } - return 0; +} + +int main(int ac, char **av) +{ + pthread_t *id; + t_philo *philo; + int i; + int n; + + philo = init(ac, av, &id); + if (philo == NULL) + return (0); + n = philo->params->n_phi; + launch_threads(philo, id, n); + i = 0; + while (i < n) + { + pthread_join(id[i], NULL); + i++; + } +write(1, "main function\n", 14); + return (0); } diff --git a/srcs/main0.c b/srcs/main0.c new file mode 100644 index 0000000..c9064db --- /dev/null +++ b/srcs/main0.c @@ -0,0 +1,23 @@ +#include "philo.h" + +void *philo_exec(void *arg) +{ + t_philo *philo; + + philo = (t_philo*)arg; + while (1) + write(1, philo->str, ft_strlen(philo->str)); +} + +int main(void) +{ + pthread_t id; + t_philo *philo; + + philo = malloc(sizeof(philo)); + philo->str = "i'm philosopher\n"; + pthread_create(&id, NULL, &philo_exec, philo); + while (1) + write(1, "main function\n", 14); + return 0; +}