4

OpenMP を使用して for ループを並列化するプログラムがあります。ループ内では、スレッドが共有変数に書き込むので、それらを同期する必要があります。ただし、セグメント フォールト、ダブル フリー、破損エラーのいずれかが発生することがあります。誰が何が起こるか知っていますか?よろしくお願いします!コードは次のとおりです。

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  
    _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);  // double free or corruption
  }  

  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] ];  // Segmentation fault
    }  
    if (result*label<0)  
    {  
    #pragma omp critical  
    {  
      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;    
            }    
          }

          ......
     }

アップデート:

私の最後の投稿double free or破損のように、コードはシングル スレッドでは問題なく実行されますが、マルチ スレッドでは実行時エラーが発生します。エラーは時々変化します。2回実行すると、1つはsegfaultになり、もう1つはダブルフリーまたは破損になります。

4

1 に答える 1

5

セグメンテーションフォールトラインを見てみましょう:

result+=_labels[ nnIdx[i] ];

resultローカルです - OK。

nnIdxローカルでもOK。

iローカルです -- それでも問題ありません。

_labels... それは何ですか?

グローバルですか?経由でアクセスを定義しました#pragma sharedか?

同じことが前者にも当てはまります:

_search_struct->annkSearch(queryPt, k_max,  nnIdx, dists, _eps);

簡単に解決できない問題があるようです -- _search_struct はスレッドセーフではありません -- おそらくその中の値はスレッドによって一度に変更されます。おそらくclassify_various_kに割り当てることにより、スレッドごとに専用の_search_structが必要です。

ただし、本当に悪いニュースは、ANN がおそらく完全に非スレッド化可能であることです。

ライブラリは少量の記憶域を割り当てます。この記憶域は、プログラムの存続期間中に構築されるすべての検索構造によって共有されます。データは共有されているため、個々の構造がすべて削除されても、割り当てが解除されることはありません。

上で見たように、ライブラリ自体にはいくつかの共有データがあるため、並列データ変更には常に問題があります。したがって、ライブラリ自体はスレッドセーフではありません:/。

于 2010-02-02T07:02:13.323 に答える