代码之家  ›  专栏  ›  技术社区  ›  Tim unnamed eng

运行多线程时双重释放或损坏

  •  7
  • Tim unnamed eng  · 技术社区  · 15 年前

    我在我的C++程序中遇到了一个运行时错误“双自由或腐败”,它调用了一个可靠的库ANN,并使用OpenMP来为循环分配一个A。

    *** glibc detected *** /home/tim/test/debug/test: double free or corruption (!prev): 0x0000000002527260 ***     
    

    这是否意味着地址0x000000002527260的内存被释放多次?

    错误发生在“_search结构->annksearch(querypt,k_max,nnidx,dists,_eps);”函数内部对_variable_k()进行分类,这反过来又发生在函数tune_complexity()内部的openmp for循环中。

    请注意,当OpenMP有多个线程时会发生错误,而在单线程情况下不会发生错误。不知道为什么。

    以下是我的代码。如果不足以诊断,请告诉我。谢谢你的帮助!

      void KNNClassifier::train(int nb_examples, int dim, double **features, int * labels) {                         
          _nPts = nb_examples;  
    
          _labels = labels;  
          _dataPts = features;  
    
          setting_ANN(_dist_type,1);   
    
        delete _search_struct;  
        if(strcmp(_search_neighbors, "brutal") == 0) {                                                                 
          _search_struct = new ANNbruteForce(_dataPts, _nPts, dim);  
        }else if(strcmp(_search_neighbors, "kdtree") == 0) {  
          _search_struct = new ANNkd_tree(_dataPts, _nPts, dim);  
          }  
    
      }  
    
    
          void KNNClassifier::classify_various_k(int dim, double *feature, int label, int *ks, double * errors, int nb_ks, int k_max) {            
            ANNpoint      queryPt = 0;                                                                                                                
            ANNidxArray   nnIdx = 0;                                                                                                         
            ANNdistArray  dists = 0;                                                                                                         
    
            queryPt = feature;     
            nnIdx = new ANNidx[k_max];                                                               
            dists = new ANNdist[k_max];                                                                                
    
            if(strcmp(_search_neighbors, "brutal") == 0) {                                                                               
              _search_struct->annkSearch(queryPt, k_max,  nnIdx, dists, _eps);    
            }else if(strcmp(_search_neighbors, "kdtree") == 0) {    
              _search_struct->annkSearch(queryPt, k_max,  nnIdx, dists, _eps); // where error occurs    
            }    
    
            for (int j = 0; j < nb_ks; j++)    
            {    
              scalar_t result = 0.0;    
              for (int i = 0; i < ks[j]; i++) {                                                                                      
                  result+=_labels[ nnIdx[i] ];    
              }    
              if (result*label<0) errors[j]++;    
            }    
    
            delete [] nnIdx;    
            delete [] dists;    
    
          }    
    
          void KNNClassifier::tune_complexity(int nb_examples, int dim, double **features, int *labels, int fold, char *method, int nb_examples_test, double **features_test, int *labels_test) {    
              int nb_try = (_k_max - _k_min) / scalar_t(_k_step);    
              scalar_t *error_validation = new scalar_t [nb_try];    
              int *ks = new int [nb_try];    
    
              for(int i=0; i < nb_try; i ++){    
                ks[i] = _k_min + _k_step * i;    
              }    
    
              if (strcmp(method, "ct")==0)                                                                                                                     
              {    
    
                train(nb_examples, dim, features, labels );// train once for all nb of nbs in ks                                                                                                
    
                for(int i=0; i < nb_try; i ++){    
                  if (ks[i] > nb_examples){nb_try=i; break;}    
                  error_validation[i] = 0;    
                }    
    
                int i = 0;    
          #pragma omp parallel shared(nb_examples_test, error_validation,features_test, labels_test, nb_try, ks) private(i)    
                {    
          #pragma omp for schedule(dynamic) nowait    
                  for (i=0; i < nb_examples_test; i++)         
                  {    
                    classify_various_k(dim, features_test[i], labels_test[i], ks, error_validation, nb_try, ks[nb_try - 1]); // where error occurs    
                  }    
                }    
                for (i=0; i < nb_try; i++)    
                {    
                  error_validation[i]/=nb_examples_test;    
                }    
              }
    
              ......
         }
    

    更新:

    谢谢!我现在正试图通过使用“pragma omp critical”来纠正在分类“variable”中写入相同内存问题的冲突:

    void KNNClassifier::classify_various_k(int dim, double *feature, int label, int *ks, double * errors, int nb_ks, int k_max) {   
      ANNpoint      queryPt = 0;    
      ANNidxArray   nnIdx = 0;      
      ANNdistArray  dists = 0;     
    
      queryPt = feature; //for (int i = 0; i < Vignette::size; i++){ queryPt[i] = vignette->content[i];}         
      nnIdx = new ANNidx[k_max];                
      dists = new ANNdist[k_max];               
    
      if(strcmp(_search_neighbors, "brutal") == 0) {// search  
        _search_struct->annkSearch(queryPt, k_max,  nnIdx, dists, _eps);  
      }else if(strcmp(_search_neighbors, "kdtree") == 0) {  
        _search_struct->annkSearch(queryPt, k_max,  nnIdx, dists, _eps);  
      }  
    
      for (int j = 0; j < nb_ks; j++)  
      {  
        scalar_t result = 0.0;  
        for (int i = 0; i < ks[j]; i++) {          
            result+=_labels[ nnIdx[i] ];  // Program received signal SIGSEGV, Segmentation fault
        }  
        if (result*label<0)  
        {  
        #pragma omp critical  
        {  
          errors[j]++;  
        }  
        }  
    
      }  
    
      delete [] nnIdx;  
      delete [] dists;  
    
    }
    

    但是,在“result+=_labels[nnidx[i]];”处有一个新的段错误。有什么想法?谢谢!

    3 回复  |  直到 6 年前
        1
  •  5
  •   Kornel Kisielewicz    15 年前

    好吧,既然您已经声明它在单线程情况下正常工作,那么“普通”方法就不会工作。您需要执行以下操作:

    • 查找并行访问的所有变量
    • 尤其地 看看那些修改过的
    • 不要对共享资源调用删除
    • 查看所有在共享资源上运行的库函数-检查它们是否不执行分配/解除分配

    这是双重删除的候选人列表:

    shared(nb_examples_test, error_validation,features_test, labels_test, nb_try, ks)
    

    此外,此代码可能不是线程安全的:

          for (int i = 0; i < ks[j]; i++) {
             result+=_labels[ nnIdx[i] ]; 
          }    
          if (result*label<0) errors[j]++;  
    

    因为两个或多个进程可能尝试对错误数组执行写操作。

    和A 大的 建议——尽量不要访问(特别是修改!)线程模式下的任何内容,都不是函数的参数!

        2
  •  4
  •   jamesdlin    15 年前

    我不知道这是不是你的问题,但是:

    void KNNClassifier::train(int nb_examples, int dim, double **features, int * labels) {
      ...
      delete _search_struct;
      if(strcmp(_search_neighbors, "brutal") == 0) {
        _search_struct = new ANNbruteForce(_dataPts, _nPts, dim);
      }else if(strcmp(_search_neighbors, "kdtree") == 0) {  
        _search_struct = new ANNkd_tree(_dataPts, _nPts, dim);
      }
    }  
    

    如果你不陷入 if else if 条款?你已经删除 _search_struct 让它指向垃圾。你应该把它设置为 NULL 之后。

    如果这不是问题所在,您可以尝试替换:

    delete p;
    

    用:

    assert(p != NULL);
    delete p;
    p = NULL;
    

    (或类似地 delete[] 站点)。(这可能会对第一次调用 KNNClassifier::train 然而,

    另外,必须:您真的需要执行所有这些手动分配和解除分配吗?你为什么不至少用 std::vector 而不是 new[] / 删除[ ] (哪一个几乎总是坏的)?

        3
  •  2
  •   Aryabhatta    15 年前

    您的train方法在分配新内存之前删除搜索结构。所以第一次叫火车时,它就被删除了。在呼叫训练之前有没有分配代码?你最终可能会试图删除垃圾内存(但我们没有代码可以告诉你)。