I am currently working on a solution for the Dining Philosophers problem in C, using multithreading with pthreads. The objective is to simulate philosophers who alternately eat and think, using forks that are shared among them. However, I’m encountering a potential deadlock issue, which I cannot seem to resolve.
Problem Description:
When running the program with two philosophers, I receive the following warnings from ThreadSanitizer indicating a potential deadlock:
Code Snippet:
Here are the relevant parts of my code that demonstrate the issue:
void meals_eaten_util(t_philo *philo)
{
philo->meals_eaten += 1;
pthread_mutex_lock(&philo->data->full_eaten);
if (!philo->eaten_enough
&& (philo->meals_eaten == philo->data->num_times_to_eat))
philo->eaten_enough = 1;
pthread_mutex_unlock(&philo->data->full_eaten);
}
int eat(t_philo *philo)
{
// Lock the left fork
if (philo->id % 2 == 1)
pthread_mutex_lock(&(philo->data->forks[philo->l_fork]));
else
pthread_mutex_lock(&(philo->data->forks[philo->r_fork]));
print_msg("has taken a fork 🍴", philo, 0);
// If only one philosopher, unlock and return
if (philo->data->num_of_philos == 1)
{
pthread_mutex_unlock(&(philo->data->forks[philo->l_fork]));
return 1;
}
// Lock the right fork
if (philo->id % 2 == 1)
pthread_mutex_lock(&(philo->data->forks[philo->r_fork]));
else
pthread_mutex_lock(&(philo->data->forks[philo->l_fork]));
print_msg("has taken a fork 🍴", philo, 0);
// Update the last meal time
pthread_mutex_lock(&philo->data->meal_lock);
philo->last_meal = get_current_time();
pthread_mutex_unlock(&philo->data->meal_lock);
print_msg("is eating 🍝", philo, 0);
ft_sleep(philo->data->time_to_eat);
meals_eaten_util(philo);
// Unlock the forks after eating
pthread_mutex_unlock(&(philo->data->forks[philo->r_fork]));
pthread_mutex_unlock(&(philo->data->forks[philo->l_fork]));
print_msg("is sleeping 💤", philo, 0);
ft_sleep(philo->data->time_to_sleep);
print_msg("is thinking 💡", philo, 0);
return 0;
}
and
void print_msg(char *str, t_philo *philo, int force)
{
size_t time;
// Try to lock the write mutex
if (pthread_mutex_lock(&philo->data->write_lock) != 0)
return; // Handle lock error if necessary
time = get_current_time() - philo->data->start_time;
// Print the message if not finished or forced to print
if (!philo->data->finished || force)
printf("%zu\t %d %s\n", time, philo->id, str);
// Always unlock the mutex at the end
pthread_mutex_unlock(&philo->data->write_lock);
}
Current Behavior:
When I run the program with two philosophers, it appears to hang after both philosophers attempt to take the forks, and the ThreadSanitizer warns of a lock-order inversion.
The output shows that both philosophers take their left and right forks, but the program stalls when they both try to lock the same mutexes.
Desired Behavior:
I would like the program to run smoothly without deadlock, allowing the philosophers to eat, think, and sleep without hanging.
Additional Information:
I have implemented mutexes for each fork, as well as additional locks for managing the state of meals eaten and writing messages.
I am using a two-philosopher setup (./philo 2 800 200 200 2) for testing.
and this is my github repo: https://github.com/negar-75/Philosophers/tree/master/philo
You need to sign in to view this answers