我正在尝试使用互斥来解决Dining-ch哲问题,但该程序可能是一个与线程相关的错误。
我在这里尝试做的基本上是将fork视为互斥并创建一个函数void *eat(void *arg)
,然后关闭关键部分(关键部分只是声明其id的线程,它目前正在吃东西(,无论函数被调用,然后我循环遍历所有的哲学家,检查它的id(id从0开始(是否可以被2整除
在一个无限循环中,第一轮只包含可被2整除的线程id,第二轮只包含不可被2除的线程id,依此类推
我知道这是一个愚蠢而简单的解决方案,可能一开始就解决不了问题。所以请耐心等待。如果你有任何问题,请在评论中告诉我。
struct typedef t_philo
{
pthread_t thread;
pthread_mutex_t fork;
int id;
}
t_philo;
void *eat(void *arg)
{
t_philo *philo = (t_philo *)arg;
pthread_mutex_lock(&philo->fork);
printf("philo with id: %i is eatingn", philo->id);
pthread_mutex_unlock(&philo->fork);
return (NULL);
}
void first_round(t_philo *philo, int len)
{
for (int i = 0; i < len; i++)
if (!(i % 2))
pthread_join(philo[i].thread, NULL);
}
void second_round(t_philo *philo, int len)
{
for (int i = 0; i < len; i++)
if ((i % 2))
pthread_join(philo[i].thread, NULL);
}
int main(int argc, char **argv)
{
t_philo *philo;
// how many philosophers is given as first arg.
int len = atoi(argv[1]);
if (argc < 2)
exit(EXIT_FAILURE);
philo = malloc(sizeof(*philo) * atoi(argv[1]));
//this function add id's and initialize some data.
init_data(philo, argv);
for (int i = 0; i < len; i++)
pthread_create(&philo[i].thread, NULL, eat(&philo[i]), &philo[i]);
while (1)
{
first_round(philo, len);
second_round(philo, len);
}
return 0;
}
输出
philo with id: 0 is eating
philo with id: 1 is eating
philo with id: 2 is eating
philo with id: 3 is eating
philo with id: 4 is eating
.
.
.
.
philo with id random is eating
[1] 29903 segmentation fault
每次输出都会到达一个随机id,并且segfault,这就是为什么我得出结论,它可能是一个线程错误。
pthread_create
有以下原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
start_routine
是函数指针。但是,您使用错误的参数调用pthread_create
:eat(&philo[i])
。因此,程序正确调用eat
,然后尝试调用NULL
(从新线程(,因为这是eat
返回的值。随机性来自于实际创建线程的可变时间。
请注意,使用调试器可以帮助您很容易地找到并解决问题。像gdb这样的调试器有点难学,但一旦完成,像segfault这样的错误几乎很容易修复。我也很惊讶像clang这样的编译器在编译时不会注意到类型问题。
在main
中,int len = argv[1];
是错误的。如果编译时启用了警告(例如-Wall
(,编译器会标记此语句。
照原样,len
会得到一个巨大的值。因此,稍后,for
循环将溢出您分配的数组,并且您有UB。
你可能想要:int len = atoi(argv[1]);
,就像你想要malloc
一样。
并且,您希望在argc
检查之后执行。
为什么要两次调用atoi
(修复(?
以下是重构后的代码:
int
main(int argc, char **argv)
{
t_philo *philo;
if (argc < 2)
exit(EXIT_FAILURE);
// how many philosophers is given as first arg.
int len = atoi(argv[1]);
philo = malloc(sizeof(*philo) * len);
// do stuff ...
return 0;
}