c -为什么我得到一个分割错误,因为我的mutex_lock?



我正在制作一个解决用餐哲学家问题的程序,当我试图锁定我的互斥锁时,我得到了一个分割错误。我不允许使用全局变量,所以我不得不用指针移动我的互斥锁,我觉得我这样做的方式是相当janky,我有点迷失在我自己的代码。下面是重要的函数

# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <pthread.h>
# include <sys/time.h>
typedef struct s_philo
{
int                 n_philo;        //* number of philosophers
int                 time_to_die;    //* time to die in ms
int                 time_to_eat;    //* time to eat in ms
int                 time_to_sleep;  //* time to sleep in ms
int                 need_eat;       //* number of times each philosopher must eat
u_int64_t           start_time;     //* time when the simulation starts
}   t_philo;
typedef struct s_data
{
pthread_mutex_t     *left_fork;     //* pointer to the left fork
pthread_mutex_t     *right_fork;    //* pointer to the right fork
u_int64_t           last_eaten;     //* time when the philosopher last ate
t_philo             *philo;         //* links to the philo struct
int                 id;             //* id of the philosopher
int                 dead;           //* 1 if the philosopher is dead
int                 is_eating;      //* 1 if the philosopher is eating
int                 n_eat;          //* number of times the philosopher has eaten
}   t_data;
u_int64_t   get_time(void);                                                             //* returns the time in ms
int         ft_usleep(useconds_t time);                                                 //* sleeps for time ms
int         ft_atoi(const char *str);                                                   //* converts a string to an int
void        init_philo(t_philo *philo, int argc, char **argv);                          //* initializes the philo struct
void        init_data(t_data *data, t_philo *philo, int id);                            //* initializes the data struct
void        *routine(void *vdata);                                                      //* routine of the philosophers
void        *monitor(void *vdata);                                                      //* monitors the philosophers (exemples: death)
int         ft_eat(void *vdata);                                                        //* eat function
int         ft_sleep(void *vdata);                                                      //* sleep function
int         ft_think(void *vdata);                                                      //* think function

int main(int argc, char **argv)
{
t_philo         philo;
t_data          data[ft_atoi(argv[1])];
pthread_t       philos[ft_atoi(argv[1])];
pthread_t       monitoring;
pthread_mutex_t forks[ft_atoi(argv[1])];
int             i;
i = 0;
init_philo(&philo, argc, argv);
while (i < philo.n_philo)
{
pthread_mutex_init(&forks[i], NULL);
i++;
}
i = 0;
while(i < philo.n_philo)
{
init_data(&data[i], &philo, i);
data->left_fork = &forks[i];
if (i == 0)
data->right_fork = &forks[philo.n_philo - 1];
else
data->right_fork = &forks[i - 1];
i++;
}
i = 0;
philo.start_time = get_time();
pthread_create(&monitoring, NULL, &monitor, &data);
while (i < philo.n_philo)
{
pthread_create(&philos[i], NULL, &routine, &data[i]);
i++;
}
i = 0;
while (i < philo.n_philo)
{
pthread_join(philos[i], NULL);
pthread_mutex_destroy(&forks[i]);
i++;
}
pthread_join(monitoring, NULL);
return (0);
}
void    *monitor(void *vdata)
{
t_data      *data;
int         i;
data = (t_data *)vdata;
i = 0;
while (1)
{
while(i < data->philo->n_philo)
{
if (get_time() - data[i].last_eaten > (u_int64_t)data[i].philo->time_to_die && data[i].last_eaten != 0 && data[i].is_eating == 0)
{
printf("%llu %d diedn", get_time() - data->philo->start_time, data->id);
data[i].dead = 1;
exit(0);
}
i++;
}
i = 0;
}
return (NULL);
}
void    *routine(void *vdata)
{
t_data  *data;
data = (t_data *)vdata;
if (data->id % 2 == 0)
ft_sleep(data);
while (data->dead == 0)
{
ft_eat(data);
ft_sleep(data);
ft_think(data);
}
return (NULL);
}
int ft_sleep(void *vdata)
{
time_t      strt;
t_data      *data;
data = (t_data *)vdata;
strt = data->philo->start_time;
printf("%llu %d is sleepingn", get_time() - strt, data->id);
ft_usleep(data->philo->time_to_sleep);
return (0);
}
int ft_eat(void *vdata)
{
time_t  strt;
t_data  *data;
data = (t_data *)vdata;
strt = data->philo->start_time;
pthread_mutex_lock(data->left_fork);
printf("%llu %d has taken a forkn", get_time() - strt, data->id);
pthread_mutex_lock(data->right_fork);
printf("%llu %d has taken a forkn", get_time() - strt, data->id);
data->is_eating = 1;
printf("%llu %d is eatingn", get_time() - strt, data->id);
ft_usleep(data->philo->time_to_eat);
data->last_eaten = get_time();
data->n_eat++;
pthread_mutex_unlock(data->left_fork);
pthread_mutex_unlock(data->right_fork);
data->is_eating = 0;
return (0);
}
int ft_think(void *vdata)
{
time_t  strt;
t_data  *data;
data = (t_data *)vdata;
strt = data->philo->start_time;
printf("%llu %d is thinkingn", get_time() - strt, data->id);
return (0);
}
int ft_usleep(useconds_t time)
{
time_t  start;
start = get_time();
while ((get_time() - start) < time)
usleep(time / 10);
return(0);
}
u_int64_t   get_time(void)
{
struct timeval  tv;

gettimeofday(&tv, NULL);
return ((tv.tv_sec * (u_int64_t)1000) + (tv.tv_usec / 1000));
}
void    init_philo(t_philo *philo, int argc, char **argv)
{
philo->n_philo = ft_atoi(argv[1]);
philo->time_to_die = ft_atoi(argv[2]);
philo->time_to_eat = ft_atoi(argv[3]);
philo->time_to_sleep = ft_atoi(argv[4]);
if (argc == 6)
philo->need_eat = ft_atoi(argv[5]);
else
philo->need_eat = -1;
philo->start_time = get_time();
}
void    init_data(t_data *data, t_philo *philo, int id)
{

data->id = id;
data->last_eaten = 0;
data->dead = 0;
data->is_eating = 0;
data->n_eat = 0;
data->philo = philo;
}

给出这个定义:

t_data          data[ft_atoi(argv[1])];

,这不会初始化所有的数据:

i = 0;
while(i < philo.n_philo)
{
init_data(&data[i], &philo, i);
data->left_fork = &forks[i];
if (i == 0)
data->right_fork = &forks[philo.n_philo - 1];
else
data->right_fork = &forks[i - 1];
i++;
}

变量data指定了一个数组,因此它在上面的表达式中出现的地方,衰减为指向第一个数组元素的指针。也就是说,您反复设置data[0]的分支,而从不设置其他元素的分支。i没有出现在表达式data中,data本身也没有被修改过,这就是你的线索。

应该这样写:

for (i = 0; i < philo.n_philo; i++) {  // prefer 'for' for simple iteration
init_data(&data[i], &philo, i);
data[i].left_fork = &forks[i];
if (i == 0) {  // never omit braces around 'if' and 'else' bodies
data[i].right_fork = &forks[philo.n_philo - 1];
} else {
data[i].right_fork = &forks[i - 1];
}
}

有了这个改变,你的程序为我运行而没有分段故障,并最终终止。

这不是答案。我懒得调试你的代码。这只是一些扩展形式的注释。


您创建了一个新线程来运行monitor(),但是main()线程除了在monitor线程运行时等待之外什么都不做。为什么要创建线程?为什么不从主线程调用monitor()呢?

注释中信息过多:例如,int time_to_die; //*time to die in ms。您可以使用int time_to_die_ms;

传递相同的信息t_philo更好的名字应该是t_parameterst_configurationt_data更好的名字应该是t_philosopherroutine()更好的名字应该是philosopher_main()

所有的void*参数和所有的类型强制转换是怎么回事?您需要void*的唯一地方是用于线程函数monitorroutine的参数。在其他任何地方,如果你想传递一个指向t_data实例的指针,参数应该声明为t_data*类型。例如,ft_eat(t_data* data)而不是ft_eat(void* vdata)

monitor()线程和routine()线程共享t_data字段的访问权限,没有任何同步。这使得程序的行为正式"未定义"。

monitor()线程旋转:不断地尽可能快地检查哲学家。这使用了整个CPU的所有可用周期,同时可能饿死其他线程。你不需要经常检查。也许在外循环中休眠一秒钟,让其他线程有机会做他们的事情。

ft_usleep()中关于毫秒和微秒的混淆。看起来每次调用它时,它将执行大约10,000次循环迭代,在每次迭代中休眠time/10000毫秒(time/10微秒)。如果您喜欢毫秒,那么除了在调用usleep()时小心且显式地之外,所有地方都使用毫秒。另外,我还去掉了循环:*

void ft_mssleep(int milliseconds) {
useconds_t microseconds = (useconds_t)1000 * milliseconds;
usleep(microseconds);
}

你有函数声明返回int总是return (0),他们的调用者从不检查返回值。为什么这些函数没有声明为返回void?

这没有任何意义:

data[i].dead = 1;
exit(0);

设置哲学家的dead标志是没有意义的,如果你做的下一件事是杀死整个程序。不妨干脆把dead旗全部去掉。如果一个哲学家"死了";因为它是死锁的,所以即使monitor()没有立即杀死整个程序,它也永远不会唤醒来检查标志。


*循环是因为您担心调用者想要睡眠超过几千秒时会溢出吗?这可能是对这个例子的需求考虑过多了,但是如果你真的想要处理这种情况,那么你可能会想做一些比你实际做的更复杂的事情。

相关内容

  • 没有找到相关文章

最新更新