From: Lukas Jiriste Date: Thu, 26 Sep 2024 08:09:49 +0000 (+0200) Subject: Make philos drop a fork when the other is taken X-Git-Url: https://git.ljiriste.work/?a=commitdiff_plain;h=74e28ef83f4e1dcd08e66fba4f618b703ccb178e;p=42%2Fphilosophers.git Make philos drop a fork when the other is taken Instead of making a fork a mutex, it now holds its state - whether it is taken. This makes it possible for a philo to check, whether he can grab both forks and if they cannot, they won't hold any fork. I thought about approach before but my mind was locked onto using the function pthread_mutex_trylock which is not permitted by the subject. --- diff --git a/philo/mem_management.c b/philo/mem_management.c index c459048..fdb9d10 100644 --- a/philo/mem_management.c +++ b/philo/mem_management.c @@ -15,6 +15,17 @@ #include #include +static void init_philo(t_diner *diner, t_philo *philo, + t_fork *fork1, t_fork *fork2) +{ + philo->forks[0] = fork1; + philo->forks[1] = fork2; + philo->settings = &diner->setting; + philo->last_eaten = 0; + philo->num_eaten = 0; + return ; +} + // Shortcircuiting does no harm here as when any mutex_init fails // the program will end anyway. int init(t_diner *diner, pthread_t **threads) @@ -32,15 +43,12 @@ int init(t_diner *diner, pthread_t **threads) i = 0; while (i < count) { - init_mutex(diner->forks + i, NULL); + init_mutex(&diner->forks[i].lock, NULL); + diner->forks[i].is_taken = 0; init_mutex(&diner->philos[i].philo_lock, NULL); - diner->philos[i].forks[i % 2] = diner->forks + i; - diner->philos[i].forks[(i + 1) % 2] = diner->forks - + (i + 1) % count; - diner->philos[i].settings = &diner->setting; - diner->philos[i].last_eaten = 0; + init_philo(diner, diner->philos + i, + diner->forks + i, diner->forks + (i + 1) % count); diner->philos[i].id = i + 1; - diner->philos[i].num_eaten = 0; ++i; } return (!all_mutexes_initialized(diner)); @@ -63,7 +71,7 @@ void cleanup(t_diner *diner, pthread_t *threads) i = 0; if (diner->forks) while (i < count) - destroy_mutex(diner->forks + (i++)); + destroy_mutex(&diner->forks[i++].lock); destroy_mutex(&diner->setting.terminal_lock); destroy_mutex(&diner->setting.end_lock); free(diner->philos); diff --git a/philo/mutex.c b/philo/mutex.c index 6073e71..cdf4611 100644 --- a/philo/mutex.c +++ b/philo/mutex.c @@ -51,7 +51,7 @@ int all_mutexes_initialized(t_diner *diner) i = 0; while (i < diner->setting.philo_count) { - res = res && diner->forks[i].is_init; + res = res && diner->forks[i].lock.is_init; res = res && diner->philos[i].philo_lock.is_init; ++i; } diff --git a/philo/philo.c b/philo/philo.c index 6dfa0fb..a2fd354 100644 --- a/philo/philo.c +++ b/philo/philo.c @@ -19,15 +19,41 @@ static void philo_think(t_philo *philo) return ; } -static void philo_eat(t_philo *philo) +static void take_forks(t_philo *philo) { - mutex_lock(philo->forks[0]); - if (report(philo, "has taken a fork")) + int i; + int forks_taken; + + i = 0; + forks_taken = 0; + while (forks_taken < 2 && !end(philo->settings)) { - mutex_unlock(philo->forks[0]); - return ; + mutex_lock(&philo->forks[i]->lock); + if (philo->forks[i]->is_taken) + { + mutex_unlock(&philo->forks[i]->lock); + if (forks_taken) + { + mutex_lock(&philo->forks[!i]->lock); + philo->forks[!i]->is_taken = 0; + mutex_unlock(&philo->forks[!i]->lock); + forks_taken = 0; + } + usleep(100); + continue ; + } + philo->forks[i]->is_taken = 1; + mutex_unlock(&philo->forks[i]->lock); + ++forks_taken; + i = !i; } - mutex_lock(philo->forks[1]); + return ; +} + +static void philo_eat(t_philo *philo) +{ + take_forks(philo); + report(philo, "has taken a fork"); report(philo, "has taken a fork"); mutex_lock(&philo->philo_lock); philo->last_eaten = usecs_since_start(philo->settings->start); @@ -35,8 +61,12 @@ static void philo_eat(t_philo *philo) mutex_unlock(&philo->philo_lock); if (!report(philo, "is eating")) usleep(philo->settings->time_to_eat); - mutex_unlock(philo->forks[0]); - mutex_unlock(philo->forks[1]); + mutex_lock(&philo->forks[0]->lock); + philo->forks[0]->is_taken = 0; + mutex_unlock(&philo->forks[0]->lock); + mutex_lock(&philo->forks[1]->lock); + philo->forks[1]->is_taken = 0; + mutex_unlock(&philo->forks[1]->lock); return ; } diff --git a/philo/philo.h b/philo/philo.h index ad3ffc9..8eeed58 100644 --- a/philo/philo.h +++ b/philo/philo.h @@ -41,13 +41,19 @@ typedef struct s_settings t_mutex end_lock; } t_settings; +typedef struct s_fork +{ + int is_taken; + t_mutex lock; +} t_fork; + typedef struct s_philosopher { unsigned int num_eaten; size_t id; useconds_t last_eaten; t_settings *settings; - t_mutex *forks[2]; + t_fork *forks[2]; t_mutex philo_lock; } t_philo; @@ -55,7 +61,7 @@ typedef struct s_diner { t_settings setting; t_philo *philos; - t_mutex *forks; + t_fork *forks; } t_diner; enum e_end