多线程环境下向std::vector添加数据偶发异常问题咨询
问题根因排查
你代码的崩溃和类地址差异无关,核心是以下几个实现错误:
- lambda捕获悬垂指针(直接触发崩溃的核心原因)
for循环中clsDP是循环内局部变量,你创建线程时用了引用捕获[&],第一次循环结束进入第二次循环时,clsDP变量本身的内存会被复用覆盖,两个线程运行时访问的clsDP大概率是无效地址或者指向同一个第二次创建的DataProcess实例,访问成员变量m_vecData自然触发异常。 - 未初始化DataStorage的存储容量
你从来没有调用过SetDataVectorSize给DataStorage的内部vector分配空间,后续DataInsertLoop直接给vecData[idx]赋值会触发数组越界。 - DataInsertLoop逻辑错误
函数入参的start和end没有被正确使用,循环条件写死成idx < _v1->size(),如果start不为0会直接导致写vecData越界。 - rand()非线程安全
C++标准库的rand()实现没有线程安全保证,多线程并发调用会触发未定义行为。 - 线程任务参数重复
两个线程的DataProcess都配置了start=0, end=halfdata,完全没有实现分片处理的逻辑,第二个线程的计算结果直接覆盖第一个的结果。
方案合理性说明
为每份分片数据创建独立DataProcess实例处理的方案本身没有问题,是多线程数据处理的常用实现,修复上述BUG即可正常运行。
修复后的核心代码示例
#include <iostream> #include <thread> #include <vector> #include <mutex> #include <random> using namespace std; static std::mutex m; class DataStorage { private: std::vector<long long> vecData; public: DataStorage() = default; ~DataStorage() = default; void SetDataVectorSize(int size) { vecData.clear(); vecData.resize(size); } void DataInsertLoop(const std::vector<long long>& _v1, long long start) { std::lock_guard<std::mutex> lock(m); // 用RAII锁避免异常时死锁 for (long long idx = 0; idx < _v1.size(); ++idx) { vecData[start + idx] = _v1[idx]; } } }; class DataProcess { private: long long m_startIndex; long long m_endIndex; DataStorage* m_mainStorage; std::vector<long long> m_vecData; std::mt19937 rng; // 线程安全的随机数生成器 public: DataProcess(long long startindex, long long endindex, unsigned int seed) : m_startIndex(startindex), m_endIndex(endindex), m_mainStorage(nullptr), rng(seed) { m_vecData.reserve(endindex - startindex); // 预分配空间避免频繁扩容 } ~DataProcess() = default; void SetMainAdrr(DataStorage* mainstorage) { m_mainStorage = mainstorage; } void DataRun() { long long num = 0; for (long long idx = m_startIndex; idx < m_endIndex; ++idx) { num += rng(); m_vecData.push_back(num); } m_mainStorage->DataInsertLoop(m_vecData, m_startIndex); } }; int main() { clock_t beginTime, endTime; DataStorage* mainStorage = new DataStorage(); const long long totalcount = 200000000; mainStorage->SetDataVectorSize(totalcount); // 先初始化存储容量 const long long halfdata = totalcount / 2; std::thread t1,t2; std::random_device rd; for (int t = 0; t < 2; ++t) { long long start = t * halfdata; long long end = (t == 1) ? totalcount : halfdata; DataProcess* clsDP = new DataProcess(start, end, rd()); clsDP->SetMainAdrr(mainStorage); // 值捕获clsDP,避免悬垂指针 if (t == 0) { t1 = std::thread([clsDP]() { clsDP->DataRun(); delete clsDP; // 用完释放内存 }); } else { t2 = std::thread([clsDP]() { clsDP->DataRun(); delete clsDP; }); } } t1.join(); t2.join(); endTime = clock(); double resultTime = (double)(endTime - beginTime); std::cout << "Multi Thread " << resultTime / 1000 << " sec" << std::endl; printf("--------------------\n"); getchar(); delete mainStorage; return 0; }
内容的提问来源于stack exchange,提问作者JasonMin
相关产品推荐
相关产品推荐

