C pthread_join()导致崩溃后指向int的指针

C pthread_join()导致崩溃后指向int的指针,c,pthreads,C,Pthreads,在修补pthreads时,我遇到了一个令人困惑的问题 如果我在pthread_join之后定义一个int指针,它似乎会使程序崩溃。在pthread_加入之前的任何地方,它都可以正常工作。我想知道为什么会这样 works.c #include <stdio.h> #include <assert.h> #include <pthread.h> #include <stdlib.h> void *somefunction(void *vargp);

在修补pthreads时,我遇到了一个令人困惑的问题

如果我在pthread_join之后定义一个int指针,它似乎会使程序崩溃。在pthread_加入之前的任何地方,它都可以正常工作。我想知道为什么会这样

works.c

#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <stdlib.h>

void *somefunction(void *vargp);


int main(int argc, char **argv){
    if (argc < 2){
        fprintf(stderr, "Invalid usage, bleh\n");
        return 1;
    }
    int argu = atoi(argv[1]);
    pthread_t tid;
    int rc = pthread_create(&tid, NULL, somefunction, &argu);
    assert (rc == 0);
    void **retval;
    int foo = 10;
    int *foo_ptr = &foo;
    pthread_join(tid, retval);
    printf("retval is %d\n", **(int **)retval);

    printf("*foo_ptr is %d\n", *foo_ptr );


    pthread_exit(NULL);
}


void *somefunction(void *vargp){
    int *someint = (int *) vargp ;
    *someint = *someint * 3;
    printf("In somefunction, someint value is %d\n", *someint);
    pthread_exit(someint);
}
#包括
#包括
#包括
#包括
void*somefunction(void*vargp);
int main(int argc,字符**argv){
如果(argc<2){
fprintf(stderr,“无效使用,bleh\n”);
返回1;
}
int argu=atoi(argv[1]);
pthread_t tid;
int rc=pthread_create(&tid,NULL,somefunction,&argu);
断言(rc==0);
作废**收回;
int-foo=10;
int*foo_ptr=&foo;
pthread_join(tid,retval);
printf(“retval是%d\n”,**(int**)retval);
printf(“*foo_ptr为%d\n”,*foo_ptr);
pthread_exit(NULL);
}
void*somefunction(void*vargp){
int*someint=(int*)vargp;
*someint=*someint*3;
printf(“在somefunction中,someint值为%d\n”,*someint);
pthread_exit(someint);
}
失败。c

如果int*foo_ptr在pthread_join()之后,则会导致我崩溃:

#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <stdlib.h>

void *somefunction(void *vargp);


int main(int argc, char **argv){
    if (argc < 2){
        fprintf(stderr, "Invalid usage, bleh\n");
        return 1;
    }
    int argu = atoi(argv[1]);
    pthread_t tid;
    int rc = pthread_create(&tid, NULL, somefunction, &argu);
    assert (rc == 0);
    void **retval;
    pthread_join(tid, retval);
    int foo = 10;
    int *foo_ptr = &foo; // <-------- this line causes a crash 
    printf("retval is %d\n", **(int **)retval);

    printf("*foo_ptr is %d\n", *foo_ptr );


    pthread_exit(NULL);
}


void *somefunction(void *vargp){
    int *someint = (int *) vargp ;
    *someint = *someint * 3;
    printf("In somefunction, someint value is %d\n", *someint);
    pthread_exit(someint);
}
#包括
#包括
#包括
#包括
void*somefunction(void*vargp);
int main(int argc,字符**argv){
如果(argc<2){
fprintf(stderr,“无效使用,bleh\n”);
返回1;
}
int argu=atoi(argv[1]);
pthread_t tid;
int rc=pthread_create(&tid,NULL,somefunction,&argu);
断言(rc==0);
作废**收回;
pthread_join(tid,retval);
int-foo=10;
int*foo_ptr=&foo;//您应该使用以下类似的用法:

void *rv;
int err;

if ((err = pthread_join(tid, &rv)) != 0)
    …report join failure using err…
else
    …rv points to what the thread returned…
这会将一个
void**
传递给
pthread\u join()
,但它与您所做的不同-它传递一个指向
void*
变量的指针,而不是未初始化的值

还要注意,返回的指针必须(应该)是指向线程函数退出后仍然存在的对象的指针—全局变量、动态分配的内存,或者可能是指向 函数在启动时通过传递给线程函数的参数或类似的方式提供内存。从线程函数堆栈返回指向
int
变量的指针是完全不可靠的。仔细研究后,代码会使用作为参数传递给fu的指针nction,所以很多都是安全的。

您应该使用以下类似的方法:

void *rv;
int err;

if ((err = pthread_join(tid, &rv)) != 0)
    …report join failure using err…
else
    …rv points to what the thread returned…
这会将一个
void**
传递给
pthread\u join()
,但它与您所做的不同-它传递一个指向
void*
变量的指针,而不是未初始化的值

还要注意,返回的指针必须(应该)是指向线程函数退出后仍然存在的对象的指针—全局变量、动态分配的内存,或者可能是指向
函数在启动时通过传递给线程函数的参数或类似的方式提供内存。从线程函数堆栈返回指向
int
变量的指针是完全不可靠的。仔细研究后,代码会使用作为参数传递给fu的指针操作,所以很多都是安全的。

在原因上转移注意力。OS X上的编译在“retval”时失败了

这里有一个“void**”,但您要做的是传入将用退出值填充的值。您需要为此创建一些存储,但所做的只是传入一个未初始化的指针

int main(int argc, char **argv){
    int argu = 21;
    pthread_t tid;
    int rc = pthread_create(&tid, NULL, somefunction, &argu);
    assert (rc == 0);
    void *retval = NULL;
    pthread_join(tid, &retval);
    int foo = 10;
    int *foo_ptr = &foo;
    printf("retval is %d\n", *(int *)retval);

    printf("*foo_ptr is %d\n", *foo_ptr );

    pthread_exit(NULL);
}

编辑:您的代码有点迟钝,但当线程关闭且其堆栈被丢弃时,“somefunction”中的“someint”消失实际上没有问题,因为“someint”实际上只是传入的值,传入的值是指向cause.Com上堆栈上的整数的指针OS X上的堆积物在“retval”爆炸

这里有一个“void**”,但您要做的是传入将用退出值填充的值。您需要为此创建一些存储,但所做的只是传入一个未初始化的指针

int main(int argc, char **argv){
    int argu = 21;
    pthread_t tid;
    int rc = pthread_create(&tid, NULL, somefunction, &argu);
    assert (rc == 0);
    void *retval = NULL;
    pthread_join(tid, &retval);
    int foo = 10;
    int *foo_ptr = &foo;
    printf("retval is %d\n", *(int *)retval);

    printf("*foo_ptr is %d\n", *foo_ptr );

    pthread_exit(NULL);
}

编辑:您的代码有点迟钝,但当线程关闭且其堆栈被丢弃时,“somefunction”中的“someint”消失实际上并没有问题,因为“someint”实际上只是传入的值,传入的值是指向
main

中堆栈上的整数的指针,当void**被替换时,它会起作用根据您的建议。问题:不仅仅是
void*retval;
就足够了,而不是
void*retval=NULL;
。?@flughting\u learner-是的,如果
pthread\u join()不使用,那么将
retval
初始化为NULL并不重要
失败。初始化它更安全。是的,这只是C多年来的一个习惯;尤其是在
void*
中。它不适用于这里的特定用例,但一般来说,它有时可以节省您的时间。由于意外的空指针取消引用导致的崩溃比由于d导致的崩溃更容易预测和调试引用一个伪随机、未初始化的值(也就是说,许多现代编译器在调试构建中自动对内存进行零初始化以帮助实现这一点)。当void**替换为您的建议时,它会起作用。问题:不只是
void*retval;
就足够了,而不是
void*retval=NULL;
。?@bulleting\u learner-是的,只要
pthread\u join()不使用它,
retval
初始化为NULL并不重要
失败。初始化它更安全。是的,这只是C多年来的一个习惯;尤其是在
void*
中。它不适用于这里的特定用例,但一般来说,它有时可以节省您的时间。由于意外的空指针取消引用而导致的崩溃比由于空指针取消引用而导致的崩溃更容易预测和调试