为什么这个多线程程序是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_createeat(&philo[i])。因此,程序正确调用 eat,然后尝试 调用 NULL(从新线程),因为这是 eat 返回的值。随机性来自实际创建线程的可变时间。

请注意,使用调试器 应该可以帮助您轻松找到并修复问题。像 gdb 这样的调试器有点难学,但一旦学会了,像 segfault 这样的错误就变得很容易修复了。我也很惊讶像 clang 这样的编译器不会在编译时注意到输入问题。