[英]Why this mutil-threaded program is Segfaulting?
我正在研究使用互斥体解决哲学家用餐问题的解决方案,但是该程序可能因与线程相关的错误而出现段错误
我在这里要做的基本上是将 fork 视为互斥锁并创建一个 function void *eat(void *arg)
,然后关闭关键部分(关键部分只是声明其 id 的线程,它的当前正在吃)无论 function 被调用什么,然后我遍历我所有的哲学家并检查它的 id(id 从 0 开始)是否可以被 2 整除。
第一轮只有线程 id 可以被 2 整除,第二轮只有线程 id 不能被 eat 整除,在无限循环中依此类推。
我知道这是一个非常简单的解决方案,可能一开始就无法解决问题。 所以请多多包涵。 如果您有任何问题,请在评论中告诉我。
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;
}
OUTPUT
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
Output 每次都达到一个随机 ID 和段错误,这就是为什么我断定它可能是一个线程错误。
pthread_create
具有以下原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
start_routine
是一个function 指针。 但是,您使用错误的 arguments调用pthread_create
: eat(&philo[i])
。 因此,程序正确调用了eat
,然后尝试调用NULL
(从新线程),因为这是eat
返回的值。 随机性来自实际创建线程的可变时间。
请注意,使用调试器应该可以帮助您轻松找到并修复问题。 像 gdb 这样的调试器有点难学,但一旦学会了,像段错误这样的错误就变得很容易修复了。 我也很惊讶像 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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.