我正在尝试使用 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);
}
我知道代码存在内存泄漏,但我的目标是在解决这个堆栈粉碎问题后解决
我查看了你的代码,我没有发现错误,这并不奇怪。
在某些时候项目变得如此之大,真的很难找到错误,如果你不在项目中就更难了。
这也是为什么 pp 要求提供一个最小的例子。
我想,是时候让你好好看看像
valgrind
、fsanitize
、gdb
、ext.这样的工具了。
为什么要创建 2 个线程/philo,而不是不使用 main 来检查死亡? 无论如何,你要做什么?
欢迎加入42大家庭。