C语言多线程:for循环中pthread_join与pthread_create的返回值指针问题
问题分析与修复
核心错误:返回值访问方式错误
你的代码中,t_returnValue是int *t_returnValue[n],即存储int指针的数组。每个线程返回的是&pp->times(也就是&t_args[j].times),所以t_returnValue[j]保存的是对应times变量的地址。
但打印时你写的(*t_returnValue)[j]是错误的:
*t_returnValue等价于t_returnValue[0],也就是第一个线程返回的地址(*t_returnValue)[j]相当于访问这个地址指向的内存的第j个int,完全偏离了预期逻辑,会越界读取栈上的随机数据,这就是你看到65、66这类异常值的原因。
正确写法应该是*t_returnValue[j],表示取第j个线程返回地址指向的int值。
潜在问题:返回栈变量地址的风险
当前代码中,线程返回的是main函数栈上t_args[j].times的地址,虽然因为main会调用pthread_join等待所有线程结束后才处理返回值,栈内存暂时有效,但这种写法不安全:如果后续修改代码,比如在pthread_join前释放了t_args或main提前退出,线程返回的地址就会变成无效野指针。
更稳妥的两种方案:
- 直接返回值(将int转为void)*:Linux系统中
int的大小不超过void*的大小,通过intptr_t做类型转换可以保证安全,直接返回times的值而非地址。 - 动态分配内存存储返回值:线程中用
malloc分配内存存储times,返回该指针,main读取后记得free避免内存泄漏。
修正后的代码
方案1:直接返回值(推荐,简单高效)
#include <stdio.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <stdint.h> // 用于intptr_t类型 #define n 5 struct print_args { int times; char characters; }; void * print_sum(void * parameters) { struct print_args * pp = (struct print_args *) parameters; for(int i=0; i<= pp->times; i++) { printf("%c", pp->characters); fflush(stdout); sleep(1); } // 用intptr_t做中转,安全转换int到void* return (void*)(intptr_t)pp->times; } int main() { pthread_t t[n]; srand(time(NULL)); struct print_args t_args[n]; char first = 'A'; void *t_returnValue[n]; // 直接存储void*类型返回值 for(int j=0; j<n; j++) { t_args[j].times = rand() % 10; t_args[j].characters = first; first++; } for(int j=0; j<n; j++) { pthread_create(&t[j], NULL, &print_sum, &t_args[j]); } for(int j=0; j<n; j++) { pthread_join(t[j], &t_returnValue[j]); } first -= n; for(int j=0; j<n; j++) { // 把void*转回int printf("\n T%c: Times %d", (char)first++, (int)(intptr_t)t_returnValue[j]); } return 0; }
方案2:动态分配内存返回值
#include <stdio.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #define n 5 struct print_args { int times; char characters; }; void * print_sum(void * parameters) { struct print_args * pp = (struct print_args *) parameters; // 分配内存存储返回值 int *ret = malloc(sizeof(int)); *ret = pp->times; for(int i=0; i<= pp->times; i++) { printf("%c", pp->characters); fflush(stdout); sleep(1); } return ret; } int main() { pthread_t t[n]; srand(time(NULL)); struct print_args t_args[n]; char first = 'A'; int *t_returnValue[n]; for(int j=0; j<n; j++) { t_args[j].times = rand() % 10; t_args[j].characters = first; first++; } for(int j=0; j<n; j++) { pthread_create(&t[j], NULL, &print_sum, &t_args[j]); } for(int j=0; j<n; j++) { pthread_join(t[j], (void **)&t_returnValue[j]); } first -= n; for(int j=0; j<n; j++) { printf("\n T%c: Times %d", (char)first++, *t_returnValue[j]); free(t_returnValue[j]); // 释放动态分配的内存 } return 0; }
验证结果
修正后运行程序,会输出每个线程正确的times值,不会再出现随机异常。
内容的提问来源于stack exchange,提问作者VuciuS
相关产品推荐
相关产品推荐

