作为引用传递的变量的值在线程中发生更改

Value of the variable passed as reference gets changed in threads

我写这个小程序是为了理解 pthread_create 和 pthread_join 但我不明白为什么变量 data 的值在 thread_join 之后被改变了。它在调用 pthread 函数后打印为 0。

#include <pthread.h>
#include <stdio.h>
void* compute_prime (void* arg)
{
        int n = *((int*) arg);
        printf("Argument passed is %d\n",n);
        return (void *)n;
}
int main ()
{
        pthread_t thread;
        int data = 5000;
        int value=0;

        pthread_create (&thread, NULL, &compute_prime, &data);
        pthread_join (thread, (void*) &value);
        printf("The number is %d and return value is %d.\n", data, value);
        return 0;
}

输出为

Argument passed is 5000
The number is 0 and return value is 5000.

这是因为pthread_join有原型void **。它需要一个指向 void * 类型对象的 指针 ;它修改了这个 void * 对象。现在碰巧你在 64 位架构上 运行,其中 datavalue 都是 32 位,并按顺序排列在内存中。修改内存中从 int 对象 value 地址开始布局的 void * 对象也会破坏 int 对象 data,因为它们都是32 位 - 因此您会看到 data 被覆盖了。但是,这是未定义的行为,因此任何事情都可能发生。


不要使用转换,因为它们只会隐藏问题。转换为 void * 特别危险,因为 void * 可以隐式转换为任何其他类型,甚至转换为 void **,尽管通常它也是不正确的。如果您删除演员表,您很可能会收到警告或类似

的错误
thrtest.c: In function ‘main’:
thrtest.c:16:31: error: passing argument 2 of ‘pthread_join’ from 
                incompatible pointer type [-Werror=incompatible-pointer-types]
         pthread_join (thread, &value);

如果在启用警告的情况下进行编译。


但是如果你真的想这样做,你必须这样做:

void *value;
pthread_join(thread, &value);
intptr_t value_as_int = (intptr_t)value;

虽然它也不是真正可移植的,因为转换是实现定义的。

return 整数最便携的方法是 return 指向 malloc 对象的指针:

int *return_value = malloc(sizeof (int));
*return_value = 42;
return return_value;

...

void *value;
pthread_join(thread, &value);
int actual = *(int *)value;
free(value);