C语言实现哲学家就餐问题遇栈溢出及线程无法终止问题求助
哲学家就餐问题:线程无法终止与栈溢出故障
问题概述
用C语言实现哲学家就餐问题时遇到两个核心问题:
- 哲学家死亡后,对应的线程无法停止
- 程序触发栈溢出(stack smashing)错误
已知代码存在内存泄漏问题,当前优先解决栈溢出故障,怀疑问题可能出在每个哲学家对应一个监视器线程的设计上。
完整代码
main.c
//main.c 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
//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
//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
//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
//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); }
调试日志
LLDB报错
* thread #2, stop reason = EXC_BAD_ACCESS (code=2, address=0x100000000) * frame #0: 0x00000001833b5a90 libsystem_pthread.dylib`_pthread_joiner_prepost_wake + 84 frame #1: 0x00000001833b3bc4 libsystem_pthread.dylib`_pthread_terminate + 300 frame #2: 0x00000001833b3a98 libsystem_pthread.dylib`_pthread_terminate_invoke + 92 frame #3: 0x00000001833b6740 libsystem_pthread.dylib`_pthread_exit + 112 frame #4: 0x00000001833b6040 libsystem_pthread.dylib`_pthread_start + 148
ThreadSanitizer报错
ThreadSanitizer:DEADLYSIGNAL ==49995==ERROR: ThreadSanitizer: SEGV on unknown address 0x000100000000 (pc 0x0001833b5a90 bp 0x00016b623f60 sp 0x00016b623f10 T300488) ==49995==The signal is caused by a WRITE memory access. ThreadSanitizer:DEADLYSIGNAL ThreadSanitizer: nested bug in the same thread, aborting.
内容的提问来源于stack exchange,提问作者Vinicius Bass
相关产品推荐
相关产品推荐

