October 21, 2024
Chicago 12, Melborne City, USA
C#

Deadlock Issue in Dining Philosophers Problem with Multithreading in C


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:
enter image description here

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

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video