为什么我的堆栈会崩溃?

问题描述 投票:0回答:1

我正在尝试使用 C 来解决 Dinning Philosophers 问题,当我哲学家死亡时,不仅我的线程不会停止,而且我还会崩溃堆栈,这是我的代码:

//main.js
static void create_threads(
    pthread_t *threads, pthread_t *death_threads,
    t_philo *philos, int n)
{
    int i;

    i = 0;
    while (i < n)
    {
        pthread_create(&threads[i], NULL, dinning_handler, &philos[i]);
        pthread_create(&death_threads[i], NULL, death_monitor, &philos[i]);
        i++;
    }
    return ;
}

static void join_threads(pthread_t *threads, pthread_t *death_threads, int n)
{
    int i;

    i = 0;
    while (i < n)
    {
        pthread_join(threads[i], NULL);
        pthread_join(death_threads[i], NULL);
        i++;
    }
    return ;
}

static void destroy_mutexes(pthread_mutex_t *forks, t_philo *philos, int n)
{
    int i;

    i = 0;
    while (i < n)
    {
        pthread_mutex_destroy(&forks[i]);
        pthread_mutex_destroy(&philos[i].last_meal_mutex);
        pthread_mutex_destroy(&philos[i].eating_mutex);
        i++;
    }
    return ;
}

static void free_resources(
    pthread_t *threads, pthread_t *death_threads,
    pthread_mutex_t *forks, t_philo *philos)
{
    free(philos);
    free(forks);
    free(threads);
    free(death_threads);
}

int main(int argc, char **argv)
{
    pthread_mutex_t *forks;
    pthread_t       *threads;
    pthread_t       *death_threads;
    t_philo         *philos;
    int             max_eats;
    pthread_mutex_t alive_mutex;

    validate_args(argc, argv);
    max_eats = -1;
    if (argc > 5)
        max_eats = ft_atoi(argv[5]);
    forks = NULL;
    threads = NULL;
    death_threads = NULL;
    philos = NULL;
    pthread_mutex_init(&alive_mutex, NULL);
    if (!init_philos(&philos, &forks, argv, max_eats, &alive_mutex))
        exit(EXIT_FAILURE);
    if (!init_threads(&threads, &death_threads, ft_atoi(argv[1])))
        exit_gracefully(philos, forks);
    create_threads(threads, death_threads, philos, ft_atoi(argv[1]));
    join_threads(threads, death_threads, ft_atoi(argv[1]));
    pthread_mutex_destroy(&alive_mutex);
    destroy_mutexes(forks, philos, ft_atoi(argv[1]));
    free_resources(threads, death_threads, forks, philos);
    return (0);
}

也许问题就在这里,事实上我每个哲学家都有一个监视器

//initialize.c
#include "philo.h"

static void fill_philos(
    char **argv, pthread_mutex_t **forks, \
    t_philo **philos, int max_eats, pthread_mutex_t *alive_mutex
)
{
    int i;
    int n_philosophers;
    int someone_die;

    n_philosophers = ft_atoi(argv[1]);
    i = 0;
    someone_die = 0;
    while (i < n_philosophers)
    {
        pthread_mutex_init(&(*forks)[i], NULL);
        pthread_mutex_init(&(*philos)[i].last_meal_mutex, NULL);
        pthread_mutex_init(&(*philos)[i].eating_mutex, NULL);
        (*philos)[i].id = i + 1;
        (*philos)[i].eats = 0;
        (*philos)[i].eating = 0;
        (*philos)[i].someone_die = &someone_die;
        (*philos)[i].time_to_eat = ft_atoi(argv[3]);
        (*philos)[i].time_to_sleep = ft_atoi(argv[4]);
        (*philos)[i].time_to_die = ft_atoi(argv[2]);
        (*philos)[i].max_eats = max_eats;
        (*philos)[i].left_fork = &(*forks)[i];
        (*philos)[i].right_fork = &(*forks)[(i + 1) % n_philosophers];
        (*philos)[i].alive_mutex = alive_mutex;
        i++;
    }
}

int init_philos(
    t_philo **philos, pthread_mutex_t **forks, \
    char **argv, int max_eats, pthread_mutex_t *alive_mutex
)
{
    int n_philosophers;

    n_philosophers = ft_atoi(argv[1]);
    (*philos) = malloc(sizeof(t_philo) * n_philosophers);
    if (!(*philos))
    {
        printf("\033[0;31mError trying to create philosophers\033[0m");
        return (0);
    }
    (*forks) = malloc(sizeof(pthread_mutex_t) * n_philosophers);
    if (!(*forks))
    {
        printf("\033[0;31mError trying to create forks\033[0m");
        return (0);
    }
    fill_philos(argv, forks, philos, max_eats, alive_mutex);
    return (1);
}

int init_threads(
    pthread_t **threads, pthread_t **death_threads,
    int n_philosophers
)
{
    (*threads) = malloc(sizeof(pthread_t) * n_philosophers);
    if (!(*threads))
    {
        printf("\033[0;31mError trying to create threads\033[0m");
        return (0);
    }
    (*death_threads) = malloc(sizeof(pthread_t) * n_philosophers);
    if (!(*death_threads))
    {
        printf("\033[0;31mError trying to create death threads\033[0m");
        return (0);
    }
    return (1);
}
//thread_handler.c

#include "philo.h"

static void eat(t_philo *philo)
{
    pthread_mutex_lock(&philo->eating_mutex);
    philo->eating = 1;
    pthread_mutex_unlock(&philo->eating_mutex);
    print_green("is eating", philo->id, get_ts_in_ms());
    pthread_mutex_lock(&philo->last_meal_mutex);
    gettimeofday(&philo->last_meal_time, NULL);
    pthread_mutex_unlock(&philo->last_meal_mutex);
    ft_usleep(philo->time_to_eat);
    philo->eats++;
    pthread_mutex_lock(&philo->eating_mutex);
    philo->eating = 0;
    pthread_mutex_unlock(&philo->eating_mutex);
}

static void p_sleep(t_philo *philo)
{
    print_blue("is sleeping", philo->id, get_ts_in_ms());
    ft_usleep(philo->time_to_sleep);
}

static void assign_fork(t_philo *philo, \
pthread_mutex_t **first, pthread_mutex_t **second)
{
    if (philo->id % 2 == 0)
    {
        (*first) = philo->left_fork;
        (*second) = philo->right_fork;
    }
    else
    {
        (*first) = philo->right_fork;
        (*second) = philo->left_fork;
    }
}

int dead_loop(t_philo *philo)
{
    pthread_mutex_lock(philo->alive_mutex);
    if (*philo->someone_die == 1)
        return (pthread_mutex_unlock(philo->alive_mutex), 1);
    pthread_mutex_unlock(philo->alive_mutex);
    return (0);
}

void    *dinning_handler(void *arg)
{
    pthread_mutex_t *first_fork;
    pthread_mutex_t *second_fork;
    t_philo         *philo;

    philo = (t_philo *)arg;

    pthread_mutex_lock(&philo->last_meal_mutex);
    gettimeofday(&philo->last_meal_time, NULL);
    pthread_mutex_unlock(&philo->last_meal_mutex);

    first_fork = NULL;
    second_fork = NULL;
    while (!dead_loop(philo) && (philo->max_eats == -1 || philo->eats < philo->max_eats))
    {
        assign_fork(philo, &first_fork, &second_fork);
        pthread_mutex_lock(first_fork);
        print_blue("has taken a fork", philo->id, get_ts_in_ms());
        pthread_mutex_lock(second_fork);
        print_blue("has taken a fork", philo->id, get_ts_in_ms());
        eat(philo);
        pthread_mutex_unlock(second_fork);
        pthread_mutex_unlock(first_fork);
        p_sleep(philo);
        print_blue("is thinking", philo->id, get_ts_in_ms());
    }
    return (NULL);
}

void    *death_monitor(void *arg)
{
    t_philo *philo;
    long    elapsed_time;
    int     is_eating;

    philo = (t_philo *)arg;
    while (!dead_loop(philo))
    {
        usleep(10000);
        pthread_mutex_lock(&philo->eating_mutex);
        is_eating = philo->eating;
        pthread_mutex_unlock(&philo->eating_mutex);
        if (is_eating)
            continue ;
        pthread_mutex_lock(&philo->last_meal_mutex);
        elapsed_time = get_elapsed_time(&philo->last_meal_time);
        pthread_mutex_unlock(&philo->last_meal_mutex);
        if (elapsed_time > philo->time_to_die)
        {
            print_red("died", philo->id, get_ts_in_ms());
            pthread_mutex_lock(philo->alive_mutex);
            *philo->someone_die = 1;
            pthread_mutex_unlock(philo->alive_mutex);
            break ;
        }
    }
    return (NULL);
}
//time_handler.c
#include "philo.h"

long    get_elapsed_time(struct timeval *start)
{
    struct timeval  now;
    long            elapsed_time;

    gettimeofday(&now, NULL);
    elapsed_time = (now.tv_sec - start->tv_sec) * 1000 + \
    (now.tv_usec - start->tv_usec) / 1000;
    return (elapsed_time);
}

long    get_ts_in_ms(void)
{
    struct timeval  time;

    gettimeofday(&time, NULL);
    return ((time.tv_sec * 1000) + (time.tv_usec / 1000));
}
//utils.c
void    exit_gracefully(t_philo *philos, pthread_mutex_t *forks)
{
    free(philos);
    free(forks);
    exit(EXIT_FAILURE);
}

void    ft_usleep(int ms)
{
    long int    time;

    time = get_ts_in_ms();
    while (get_ts_in_ms() - time < ms)
        usleep(ms / 10);
}

我知道代码存在内存泄漏,但我的目标是在解决这个堆栈粉碎问题后解决

c multithreading stack
1个回答
0
投票

嗯,这真的难以阅读。

我查看了你的代码,我没有发现错误,这并不奇怪。

在某些时候项目变得如此之大,真的很难找到错误,如果你不在项目中就更难了。

这也是为什么 pp 要求提供一个最小的例子

我想,是时候让你好好看看像

valgrind
fsanitize
gdb
、ext.

这样的工具了。

为什么要创建 2 个线程/philo,而不是不使用 main 来检查死亡? 无论如何,你要做什么?

欢迎加入42大家庭。

© www.soinside.com 2019 - 2024. All rights reserved.