为什么main函数无法将正确的参数传递给pthread_creat函数

时间:2019-11-15 13:23:46

标签: c++

我试图通过限制4点进餐的哲学家的数量来解决哲学家的问题。在主函数中,我这样编写代码以创建线程。

for (i = 0; i < N; i++) {
        pthread_create(&tidp[i], NULL, creatPhilosopher, (void *)&i);
    }

但这是输出

philosopher 0 is thinking...
philosopher 0 is thinking...
philosopher 0 is thinking...
philosopher 0 is thinking...
philosopher 0 is thinking...
philosopher 0 is eating...
philosopher 0 is eating...
philosopher 0 is eating...
philosopher 0 is eating...
philosopher 0 is eating...

同时,我尝试了另一种方法

 for (i = 0; i < N; i++) {
        int* temp = (int*)malloc(sizeof(int));
        *temp = i;
        pthread_create(&tidp[i], NULL, creatPhilosopher, (void *)temp);
    }

输出正确。

philosopher 4 is thinking...
philosopher 3 is thinking...
philosopher 2 is thinking...
philosopher 1 is thinking...
philosopher 0 is thinking...
philosopher 4 is eating...
philosopher 3 is eating...
philosopher 2 is eating...
philosopher 1 is eating...
philosopher 0 is eating...
philosopher 4 is thinking...
philosopher 3 is thinking...
philosopher 2 is thinking...
philosopher 1 is thinking...

那么,两种方式有什么区别?

3 个答案:

答案 0 :(得分:2)

在第一种情况下,只有一个存储位置传递给所有不同的线程:变量i的地址。因此,所有线程将从相同位置读取其编号。他们从那里读取的内容取决于他们何时读取该值。全部都读为0似乎有点奇怪,但是无论如何,这不是您想要的。

在第二种情况下,为每个线程分配一个不同内存位置。因此,每个线程从不同的位置读取数据,因此从不同的编号读取数据。

答案 1 :(得分:0)

在第一个示例中,您将每个线程的指针/引用/句柄传递给相同的变量。一个变量保存一个值。您也不会同步对该变量的访问(更不用说它可能在每个线程试图读取该变量之前被销毁),因此实际上所有赌注都没有了。

在第二个示例中,每个线程都获得具有正确值的i的副本,并且由于变量是独立的对象,因此您也具有线程安全性。

您应该始终在考虑对象的生存期,所有权和访问模式。

答案 2 :(得分:0)

区别是未定义的行为。

for (i = 0; i < N; i++) {
     pthread_create(&tidp[i], NULL, creatPhilosopher, (void *)&i);
}

无论您使用的C ++标准还是POSIX(其线程API),都不能保证createPhilosopher将开始执行并读取在{{之前传递给它的指针的值。 1}}循环的迭代完成,因此新线程将读取for的当前值。无法保证i实际上会在createPhilosopher返回主执行线程之前真正开始执行。可能会或可能不会。这取决于月亮的相位和潮汐。

当执行线程开始执行时,整个pthread_create循环很可能已经完成,并且只是一个遥远的内存。它多次调用for(但是它们的执行线程尚未开始执行),实际上,pthread_create变量现在已被销毁并且不再存在(无论在何处声明),现在它的内存已被其他一些随机选择的值占用,或者是垃圾,因此当新的执行线程读取它们作为参数接收的指针时,它就指向垃圾。

在另一种情况下,您将在动态范围内分配单个i值,当执行线程实际开始执行时,该值仍然存在,因此它们读取该值。 int没有它们,因此指针仍然是值。而且您泄漏了内存,但这是另一个故事。