Make philos drop a fork when the other is taken
authorLukas Jiriste <ljiriste@student.42prague.com>
Thu, 26 Sep 2024 08:09:49 +0000 (10:09 +0200)
committerLukas Jiriste <ljiriste@student.42prague.com>
Thu, 26 Sep 2024 08:09:49 +0000 (10:09 +0200)
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.

philo/mem_management.c
philo/mutex.c
philo/philo.c
philo/philo.h

index c4590485ac9124c72e80afa35996d13ba892b832..fdb9d103558092c7c0bdd253456c125a8b82436d 100644 (file)
 #include <stddef.h>
 #include <stdlib.h>
 
+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);
index 6073e71f723b92f3dffc990e5617ef5d75033ce4..cdf4611453670865a7a65f29379c89142f84b1e8 100644 (file)
@@ -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;
        }
index 6dfa0fb03458a8f0399e72ca77553e82c6d9fce6..a2fd35403dbc31b8d9046614d0de74142c0c0d23 100644 (file)
@@ -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 ;
 }
 
index ad3ffc9bf6c8ad1b275582521366e5ad2c0859a1..8eeed5894459834160b2d9dc4bfbd1c22a29467b 100644 (file)
@@ -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