pthread_join()后定义int指针引发程序崩溃的原因咨询
这问题看起来有点迷惑,但核心原因其实和变量定义位置无关,而是你对pthread_join的参数使用有误,之前的“正常运行”只是巧合的未定义行为结果!
核心错误:未初始化的retval指针
pthread_join的第二个参数要求传入一个指向void*类型的指针(也就是void**),目的是让函数把线程退出时返回的指针值写入到这个地址指向的内存中。
但你的代码里,retval是一个未初始化的void**变量:
void **retval; pthread_join(tid, retval);
这意味着retval里存的是一个随机的内存地址,pthread_join会尝试往这个随机地址写数据——这属于未定义行为,程序可能崩溃、可能看似正常运行,完全取决于这个随机地址是否属于程序有权限访问的内存区域。
为什么works.c看似正常?
当你在pthread_join之前定义foo和foo_ptr时,栈上的内存布局刚好让未初始化的retval指向了一块程序有权访问的内存(比如栈上的某个空闲区域),所以pthread_join的写入操作没有触发崩溃。但这完全是运气,代码本身依然是错误的,换个环境、换个编译参数可能就会崩溃。
为什么fails.c会崩溃?
当你把foo_ptr移到pthread_join之后,栈的布局发生了变化,未初始化的retval指向的是一块程序无权访问的内存(比如栈外的地址,或者还未被分配的栈空间),pthread_join尝试往这里写数据时就触发了段错误,导致程序崩溃。
正确的写法
你需要定义一个void*类型的变量,然后把它的地址传给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; // 定义一个void*变量,用来存储线程返回值 pthread_join(tid, &retval); // 传递这个变量的地址给pthread_join 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); } void *somefunction(void *vargp){ int *someint = (int *) vargp ; *someint = *someint * 3; printf("In somefunction, someint value is %d\n", *someint); pthread_exit(someint); }
另外补充一点:你的线程返回的是main函数栈上变量argu的地址,这里因为pthread_join会等待线程结束后才继续执行,所以argu的生命周期是安全的;但如果线程是分离的或者没有被等待,返回栈变量的地址会导致悬空指针问题,这点需要注意。
内容的提问来源于stack exchange,提问作者struggling_learner

