From 34f24a6bc5862a13b98cc538e3b30b87abf7abf8 Mon Sep 17 00:00:00 2001 From: Lukas Jiriste Date: Thu, 7 Mar 2024 17:52:47 +0100 Subject: [PATCH] Implement mandatory part of philosophers Sorry for big commit, I wrote it in one session and didn't encounter an apropriate point for partial commit. This needs to be tested and refactored to pass the 42 Norm. --- philo/Makefile | 30 +++++ philo/main.c | 353 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 383 insertions(+) create mode 100644 philo/Makefile create mode 100644 philo/main.c diff --git a/philo/Makefile b/philo/Makefile new file mode 100644 index 0000000..1a6a033 --- /dev/null +++ b/philo/Makefile @@ -0,0 +1,30 @@ +CC := gcc + +CFLAGS := -Wall -Wextra -Werror -Wpedantic +#-std=c99 +NAME := philo + +SRCDIR := . +SRCS := main.c +SRCS := $(addprefix $(SRCDIR)/, $(SRCS)) +OBJS := $(SRCS:%.c=%.o) + +all : $(NAME) + +debug : CFLAGS += -g +debug : $(NAME) + +$(NAME) : $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $@ + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean : + $(RM) $(OBJS) + +fclean : + $(RM) $(OBJS) $(NAME) + +re : fclean + $(MAKE) diff --git a/philo/main.c b/philo/main.c new file mode 100644 index 0000000..31fb432 --- /dev/null +++ b/philo/main.c @@ -0,0 +1,353 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/05 12:49:40 by ljiriste #+# #+# */ +/* Updated: 2024/03/07 17:51:19 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include +#include +#include +#include + +// unsigned long would be more apropriate for min_eats_num +// but for the ease of parsing I'm using size_t +typedef struct s_settings +{ + int end; + size_t min_eats_num; + size_t philo_count; + suseconds_t time_to_die; + suseconds_t time_to_eat; + suseconds_t time_to_sleep; + suseconds_t program_start; + pthread_mutex_t terminal; +} t_settings; + +typedef struct s_philo +{ + size_t times_eaten; + size_t id; + suseconds_t last_eaten; + pthread_mutex_t *forks[2]; + t_settings *settings; +} t_philo; + +suseconds_t cur_time_sus(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000000 + tv.tv_usec); +} + +void thread_print(t_settings *set, size_t id, const char *message) +{ + pthread_mutex_lock(&set->terminal); + if (set->end) + { + pthread_mutex_unlock(&set->terminal); + return ; + } + printf("%li %li %s\n", (cur_time_sus() - set->program_start) / 1000, id, message); + pthread_mutex_unlock(&set->terminal); + return ; +} + +void philo_sleep(t_settings *set, size_t id) +{ + thread_print(set, id, "is sleeping"); + usleep(set->time_to_sleep); + return ; +} + +void philo_think(t_settings *set, size_t id) +{ + thread_print(set, id, "is thinking"); + return ; +} + +int philo_eat(t_philo *philo) +{ + pthread_mutex_lock(philo->forks[0]); + thread_print(philo->settings, philo->id, "has taken a fork"); + pthread_mutex_lock(philo->forks[1]); + thread_print(philo->settings, philo->id, "has taken a fork"); + thread_print(philo->settings, philo->id, "is eating"); + philo->last_eaten = cur_time_sus(); + usleep(philo->settings->time_to_eat); + pthread_mutex_unlock(philo->forks[0]); + pthread_mutex_unlock(philo->forks[1]); + return (0); +} + +void *be_a_philosopher(void *inp) +{ + t_philo *philo; + + philo = (t_philo *)inp; + philo->last_eaten = philo->settings->program_start; + while (!philo->settings->end) + { + philo_think(philo->settings, philo->id); + if (philo_eat(philo) == 1) + break ; + ++philo->times_eaten; + if (philo->times_eaten == philo->settings->min_eats_num) + return (NULL); + philo_sleep(philo->settings, philo->id); + } + return (NULL); +} + +pthread_mutex_t *init_forks(size_t count) +{ + pthread_mutex_t *forks; + + forks = malloc(sizeof(pthread_mutex_t) * count); + if (!forks) + return (NULL); + while (count > 0) + { + pthread_mutex_init(&forks[--count], NULL); + } + return (forks); +} + +t_philo *build_philos(pthread_mutex_t *forks, t_settings *set) +{ + t_philo *philos; + size_t count; + + if (!forks) + return (NULL); + count = set->philo_count; + philos = malloc(sizeof(t_philo) * count); + if (!philos) + return (NULL); + philos[0].forks[1] = forks + count - 1; + while (count > 0) + { + --count; + philos[count].id = count + 1; + philos->times_eaten = 0; + philos[count].settings = set; + philos[count].forks[0] = forks + count - count % 2; + if (count > 0) + philos[count].forks[1] = forks + count - (count + 1) % 2; + } + return philos; +} + +size_t ft_atos(const char *str) +{ + size_t res; + + res = 0; + while (*str == ' ') + ++str; + if (*str == '+') + ++str; + while ('0' <= *str && *str <= '9') + { + res *= 10; + res += *str - '0'; + ++str; + } + return (res); +} + +static size_t size_needed(int n) +{ + size_t res; + + res = 1; + if (n == 0) + return (2); + if (n < 0) + ++res; + while (n != 0) + { + ++res; + n /= 10; + } + return (res); +} + +char *ft_stoa(int n) +{ + size_t size; + char *res; + + size = size_needed(n); + res = malloc(size * sizeof(char)); + if (res == NULL) + return (res); + res[--size] = '\0'; + if (n == 0 && res) + res[0] = '0'; + else if (n < 0 && res) + { + res[0] = '-'; + res[--size] = '0' - (n % 10); + n = -(n / 10); + } + while (n > 0 && res) + { + res[--size] = '0' + (n % 10); + n /= 10; + } + return (res); +} + +int ft_strcmp(const char *s1, const char *s2) +{ + size_t i; + + i = 0; + while (s1[i] == s2[i] && s1[i] && s2[i]) + ++i; + return ((unsigned char)s1[i] - (unsigned char)s2[i]); +} + +int parse_args(const char *arg, size_t *val) +{ + int res; + char *check_str; + + *val = ft_atos(arg); + check_str = ft_stoa(*val); + while (*arg == ' ' || *arg == '+') + ++arg; + res = ft_strcmp(check_str, arg); + free(check_str); + return (res); +} + +int parse_arg(const char *arg, suseconds_t *val) +{ + size_t tmp; + + if (parse_args(arg, &tmp)) + return (1); + *val = tmp; + if (*val != ((*val * 1000) / 1000)) + return (1); + *val *= 1000; + return (0); +} + +int parse_input(int argc, char **argv, t_settings *set) +{ + int res; + + if (argc != 5 && argc != 6) + return (0); + res = 0; + res = res || parse_args(argv[1], &set->philo_count); + res = res || parse_arg(argv[2], &set->time_to_die); + res = res || parse_arg(argv[3], &set->time_to_eat); + res = res || parse_arg(argv[4], &set->time_to_sleep); + if (argc == 6) + res = res || parse_args(argv[5], &set->min_eats_num); + else + set->min_eats_num = 0; + return (res); +} + +int init_settings(int argc, char **argv, t_settings *set) +{ + pthread_mutex_init(&set->terminal, NULL); + set->end = 0; + return (parse_input(argc, argv, set)); +} + + +void cleanup(pthread_mutex_t *forks, t_philo *philos, pthread_t *threads, t_settings *set) +{ + size_t count; + + count = set->philo_count; + while (count > 0) + { + --count; + pthread_mutex_destroy(&forks[count]); + } + pthread_mutex_destroy(&set->terminal); + free(forks); + free(philos); + free(threads); + return ; +} + +void create_philos(t_philo *philos, pthread_t *threads, size_t count) +{ + while (count > 0) + { + --count; + pthread_create(threads + count, NULL, be_a_philosopher, philos + count); + } + return ; +} + +void check_death(t_philo *philos, t_settings *set) +{ + suseconds_t oldest; + suseconds_t now; + size_t i; + + while (1) + { + i = 0; + now = cur_time_sus(); + while (i < set->philo_count) + { + oldest = philos[0].last_eaten; + if((now - philos[i].last_eaten) > set->time_to_die) + { + pthread_mutex_lock(&set->terminal); + printf("%li %lu %s\n", (cur_time_sus() - set->program_start) / 1000, i + 1, "died"); + set->end = 1; + pthread_mutex_unlock(&set->terminal); + return ; + } + if (oldest > philos[i].last_eaten) + oldest = philos[i].last_eaten; + ++i; + } + now = cur_time_sus(); + //usleep(now - oldest); + } +} + +int main(int argc, char **argv) +{ + t_settings settings; + pthread_mutex_t *forks; + pthread_t *threads; + t_philo *philos; + + if (init_settings(argc, argv, &settings)) + return (1); + threads = malloc(sizeof(pthread_t) * settings.philo_count); + forks = init_forks(settings.philo_count); + philos = build_philos(forks, &settings); + if (!forks || !threads || !philos) + { + cleanup(forks, philos, threads, &settings); + return (2); + } + settings.program_start = cur_time_sus(); + create_philos(philos, threads, settings.philo_count); + usleep(settings.time_to_die / 10); + check_death(philos, &settings); + cleanup(forks, philos, threads, &settings); + return (0); +} -- 2.30.2