为何向pthread_exit()传递void*返回值时一种方式结果异常?
问题背景
初次学习POSIX线程编程时,测试两种向pthread_exit()传递void*类型返回值的写法,发现仅一种写法可以得到预期结果,复现场景如下。
复现代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> static void *threadFunction(void *arg) { printf("thread1: hello from thread...\n"); char array_of_chars[] = "goodbye..."; char *ptr_to_first_element_in_array_of_chars = array_of_chars; void *exitStatus_ptr; exitStatus_ptr = ptr_to_first_element_in_array_of_chars; printf("thread1: thread about to die...\n"); //pthread_exit( exitStatus_ptr ); /** denote as Line 17 **/ pthread_exit((void *) "goodbye..."); /** denote as Line 18 **/ } int main(int argc, int *argv[]) //main thread { pthread_t thread1; void *targetThread_exitStatus; int s; s = pthread_create(&thread1, NULL, threadFunction, NULL); if (s != 0) { perror("pthread_create() error..."); } s = pthread_join(thread1, &targetThread_exitStatus); if (s != 0) { perror("pthread_join() error..."); } printf("main thread: retval from thread is: %s\n", (char*) targetThread_exitStatus); printf("main thread: thread about to die...\n"); pthread_exit(NULL); }
复现操作与现象
在Linux终端执行编译命令:gcc code.c -lpthread -o code
编译完成后运行./code,两种写法的运行表现存在明显差异:
- 启用标注为Line18的
pthread_exit((void *) "goodbye...");语句、注释Line17时,运行结果符合预期,主线程可正确打印线程返回的字符串"goodbye..." - 注释Line18、启用标注为Line17的
pthread_exit( exitStatus_ptr );语句时,主线程无法打印出正确的返回字符串内容。
这里存在一个明显的疑问:C语言中字符串以字符数组形式存储,数组名会退化为指向首元素的指针,为何两种传参方式仅有一种可得到预期结果?
原因解析
两种写法的核心差异是传给pthread_exit的指针指向的内存生命周期完全不同,和数组退化规则没有关系。
- Line18写法生效的原因
代码中的"goodbye..."是字符串字面量,程序编译时这类内容会被存放到进程的只读数据段,内存生命周期覆盖程序整个运行周期,不会因为线程退出、函数返回被回收或覆写。pthread_exit传递的指针指向这块永久合法的内存,主线程调用pthread_join拿到指针时,内存内容依然完整有效,因此可以正常打印字符串。 - Line17写法失效的原因
线程函数内定义的char array_of_chars[] = "goodbye...";是分配在线程栈上的局部数组,内存生命周期仅在threadFunction函数执行期间有效。当线程调用pthread_exit退出、线程函数执行结束后,这块栈内存会被系统回收,后续随时可能被其他操作覆写内容。
此时传给pthread_exit的exitStatus_ptr是指向已回收栈内存的野指针,主线程拿到指针后读取内存时,原位置存储的字符串早就被破坏,自然无法打印出正确内容。
注意:数组退化为指针仅代表指针的值(内存地址)和数组首元素地址一致,不代表指针指向的内存会一直保持有效。只要指向的内存生命周期结束,无论指针值本身看起来多么“正确”,解引用操作都属于未定义行为,结果不可预期。
线程返回字符串的正确实现方式
如果需要通过pthread_exit返回字符串,可以选择以下几种合法写法:
- 直接返回字符串字面量(即Line18的写法,注意不要尝试修改字面量内容,否则会触发段错误)
- 在线程函数内调用
malloc从堆上分配内存存储字符串,将堆指针作为返回值传递,主线程拿到指针使用完成后需要调用free释放内存,避免内存泄漏 - 将待返回的内容存储到全局变量、或者主线程通过线程参数传入的合法内存块中,保证这块内存在
pthread_join执行完成前不会被释放或覆写
内容的提问来源于stack exchange,提问作者jvwm
相关产品推荐
相关产品推荐

