为什么这个多线程程序是Segfaulting?
Why this mutil-threaded program is Segfaulting?
我正在研究使用互斥体解决哲学家用餐问题的方法,但是该程序可能由于与线程相关的错误而出现段错误
我在这里尝试做的基本上是想到叉子作为互斥锁并创建一个函数 void *eat(void *arg)
,然后关闭关键部分(关键部分只是声明其 id 和它当前正在吃的线程)无论调用什么函数,然后我循环遍历我的所有philosophers 并检查它的 id(id 从 0 开始)是否可以被 2 整除。
第一轮只有线程 id 可以被 2 整除,第二轮只有线程 id 不能被 2 整除,依此类推无限循环.
我知道这是一个愚蠢的简单解决方案,可能无法首先解决问题。所以请多多包涵。如果您有任何问题,请在评论中告诉我。
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 eating\n", 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 和段错误,这就是为什么我断定它可能是一个线程错误。
在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;
}
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 这样的编译器不会在编译时注意到输入问题。
我正在研究使用互斥体解决哲学家用餐问题的方法,但是该程序可能由于与线程相关的错误而出现段错误
我在这里尝试做的基本上是想到叉子作为互斥锁并创建一个函数 void *eat(void *arg)
,然后关闭关键部分(关键部分只是声明其 id 和它当前正在吃的线程)无论调用什么函数,然后我循环遍历我的所有philosophers 并检查它的 id(id 从 0 开始)是否可以被 2 整除。
第一轮只有线程 id 可以被 2 整除,第二轮只有线程 id 不能被 2 整除,依此类推无限循环.
我知道这是一个愚蠢的简单解决方案,可能无法首先解决问题。所以请多多包涵。如果您有任何问题,请在评论中告诉我。
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 eating\n", 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 和段错误,这就是为什么我断定它可能是一个线程错误。
在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;
}
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 这样的编译器不会在编译时注意到输入问题。