gcc5.4 CentOS7下多线程调用unit_thread_data时析构函数触发段错误求助
问题根因分析
- 重复释放内存触发double free
你在unit_thread_data函数中已经手动执行delete[] pthread_data[i].d->A_;释放了数组内存,后续执行delete pthread_data[i].d;时,Data类的析构函数会再次尝试释放A_指向的内存,此时A_已经是野指针,二次释放直接触发段错误。 - new[]与delete运算符不匹配导致未定义行为
线程函数_add中给A_分配内存使用的是数组分配运算符new int[2],但Data析构函数中使用的是普通释放运算符delete A_,不符合C++语法规范,即使没有重复释放的问题也会产生不可预知的运行异常。
修复方案
方案1(推荐):由类析构函数全权负责成员内存释放,移除手动释放逻辑
修改两处代码即可:
- 修正
Data类析构函数的释放运算符,把delete A_;改为delete[] A_; - 移除
unit_thread_data函数中手动释放A_的代码行delete[] pthread_data[i].d->A_;
方案2:保留手动释放逻辑,释放后置空指针避免二次释放
如果业务需要手动提前释放A_内存,修改三处代码:
- 修正
Data类析构函数的释放运算符为delete[] A_; - 在
unit_thread_data中执行delete[] pthread_data[i].d->A_;之后,新增一行pthread_data[i].d->A_ = NULL;,这样析构函数判断A_为NULL就不会再次释放。
修复后完整代码示例
#include <iostream> #include <pthread.h> #include <unistd.h> using namespace std; class Data { public: int* A_; Data() { cout<<"111\n"; A_=NULL; } ~Data() { cout<<"222\n"; if(A_) { delete[] A_; // 修正为delete[]匹配new[] } } }; struct thread_data_t { Data* d; }; void* _add(void* _pthread_data) { thread_data_t* pthread_data = (thread_data_t*) _pthread_data; pthread_data->d->A_ = new int[2]; pthread_data->d->A_[0] = 1; pthread_data->d->A_[1] = 2; std::cout<<pthread_data->d->A_[0]+pthread_data->d->A_[1]<<endl; return (void*)0; } void unit_thread_data(thread_data_t* pthread_data) { for(int i=0;i<2;i++) { // 移除手动释放A_的代码,交由析构函数处理 delete pthread_data[i].d; } delete[] pthread_data; } int main() { int num_threads = 2; pthread_t threads[num_threads]; thread_data_t* pthread_data = new thread_data_t[num_threads]; for(int i=0;i<num_threads; i++) { pthread_data[i].d = new Data(); } for (int i=0; i<num_threads; i++) { pthread_create(&threads[i], NULL, _add, (void*)(pthread_data+i)); } for (int i=0; i<num_threads; i++) { pthread_join(threads[i], NULL); } sleep(1); unit_thread_data(pthread_data); return 0; }
内容的提问来源于stack exchange,提问作者IDO
相关产品推荐
相关产品推荐

