C++多线程场景下如何从父线程或子线程向孙线程传递数值
问题修复说明
核心错误点
- 子线程中
childInfo、GCarg使用static修饰,属于全局共享变量,多个子线程并行执行时会互相覆盖数据,导致传参混乱 info结构体中的digit、totalDigits仅分配了1个int的内存,后续作为数组存储多位数时直接越界访问,引发未定义行为- 多处数组索引逻辑错误,对指针类型的结构体成员访问时索引逻辑完全混乱
- 文件读取使用
eof()判断终止条件,会多读一行无效数据 - 存在大量内存泄漏,动态分配的内存未正确释放
修复后完整代码
#include <iostream> #include <pthread.h> #include <math.h> #include <fstream> #include <cstdlib> #include <unistd.h> using namespace std; // 简化结构体,去掉不必要的指针避免越界 struct grandchildThreadData { int GCTDdigit; int GCTDchildIndex; // 所属子线程序号 int GCTDgrandchildIndex; // 孙线程自身序号 }; struct childThreadData { long int CTDlineValue; int CTDchildIndex; }; // 线程函数声明 void* childThread(void*); void* grandchildThread(void*); // 数值拆分为单个数字的函数 int* digitSeparator(long int, int&); int main() { // 读取文件统计行数,同时读取内容 int totalLines{0}; ifstream file("file.txt"); string temp; // 先统计行数 while (getline(file, temp)) { if (!temp.empty()) totalLines++; // 跳过空行 } file.clear(); file.seekg(0); // 重置文件指针到开头 long int* valueOnLine = new long int[totalLines]; for (int i = 0; i < totalLines; i++) { file >> valueOnLine[i]; } file.close(); pthread_t* child = new pthread_t[totalLines]; childThreadData* Carg = new childThreadData[totalLines]; // 创建子线程 for (int i = 0; i < totalLines; i++) { Carg[i].CTDchildIndex = i; Carg[i].CTDlineValue = valueOnLine[i]; if (pthread_create(&child[i], nullptr, childThread, &Carg[i])) { fprintf(stderr, "Error creating child thread\n"); return 1; } } // 等待所有子线程结束 for (int i = 0; i < totalLines; i++) { if (pthread_join(child[i], nullptr)) { fprintf(stderr, "Error joining child thread\n"); return 2; } } // 释放内存 delete[] valueOnLine; delete[] child; delete[] Carg; return 0; } void* childThread(void* arg) { childThreadData* CTptr = (childThreadData*)arg; int totalDigits = 0; int* numberArray = digitSeparator(CTptr->CTDlineValue, totalDigits); pthread_t* grandchild = new pthread_t[totalDigits]; grandchildThreadData* GCarg = new grandchildThreadData[totalDigits]; // 去掉static,每个子线程有独立的参数数组 // 创建孙线程 for (int i = 0; i < totalDigits; i++) { GCarg[i].GCTDchildIndex = CTptr->CTDchildIndex; GCarg[i].GCTDgrandchildIndex = i; GCarg[i].GCTDdigit = numberArray[i]; if (pthread_create(&grandchild[i], nullptr, grandchildThread, &GCarg[i])) { fprintf(stderr, "Error creating grandchild thread\n"); } } // 等待所有孙线程结束 for (int i = 0; i < totalDigits; i++) { pthread_join(grandchild[i], nullptr); } // 释放内存 delete[] numberArray; delete[] grandchild; delete[] GCarg; return nullptr; } void* grandchildThread(void* arg) { grandchildThreadData* GCTptr = (grandchildThreadData*)arg; // 注:cout不是线程安全的,多线程同时输出可能出现乱序,属于正常现象 cout << "子线程" << GCTptr->GCTDchildIndex << " 孙线程" << GCTptr->GCTDgrandchildIndex << " 收到数字:" << GCTptr->GCTDdigit << endl; return nullptr; } int* digitSeparator(long int number, int& totalDigits) { totalDigits = log10((float)number) + 1; int* separatorPtr = new int[totalDigits]; int j = 0; for (int i = totalDigits - 1; i >= 0; i--) { long int divisor = pow((float)10, i); long int digit = number / divisor; number -= digit * divisor; separatorPtr[j] = digit; j++; } return separatorPtr; }
测试说明
针对示例file.txt:
1234 567 8910
运行后会输出11条结果(4+3+4),包含所有拆分后的数字,线程调度顺序不同输出顺序会有差异,所有数字传递均正确。
内容的提问来源于stack exchange,提问作者MWaleed Malik
相关产品推荐
相关产品推荐

