2010-02-02 16 views
7

मैं अपने सी ++ प्रोग्राम में एक रनटाइम त्रुटि "डबल फ्री या भ्रष्टाचार" से मिला जो विश्वसनीय पुस्तकालय एएनएन कहता है और लूप के लिए लंबित करने के लिए ओपनएमपी का उपयोग करता है।डबल फ्री या भ्रष्टाचार

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

क्या इसका मतलब यह है कि 0x0000000002527260 पते पर स्मृति एक से अधिक बार मुक्त हो गई है?

त्रुटि "_search_struct-> annkSearch (queryPt, k_max, nnIdx, dists, _eps) पर होती है;" फ़ंक्शन classify_various_k() के अंदर, जो फ़ंक्शन tune_complexity() के अंदर ओपनएमपी फॉर-लूप के अंदर बदले में है।

ध्यान दें कि त्रुटि तब होती है जब ओपनएमपी के लिए एक से अधिक धागे होते हैं, और एकल थ्रेड मामले में नहीं होते हैं। यकीन नहीं है कि क्यों।

मेरा कोड निम्नलिखित है। यदि यह निदान के लिए पर्याप्त नहीं है, तो बस मुझे बताएं। आपकी सहायताके लिए धन्यवाद!

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 महत्वपूर्ण" का उपयोग करके classify_various_k() में एक ही स्मृति समस्या को लिखित रूप से संघर्ष को दूर करने के कोशिश कर रहा हूँ:

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; 

} 

हालांकि, वहाँ परिणाम में "एक नया सेगमेंट गलती त्रुटि + = _ लेबल [nnIdx है [मैं] ];"। कुछ विचार? धन्यवाद!

+0

इसे openmp के बिना आज़माएं - क्या यह सही तरीके से काम करता है? –

+1

यदि आप ओएसएक्स या लिनक्स पर हैं तो मैं -g और valgrind के माध्यम से चलने की अनुशंसा करता हूं। यह आपके लिए त्रुटि को इंगित करना चाहिए। –

+0

@ कॉर्नेल: यह सिंगल-थ्रेड केस के लिए सही तरीके से काम करता है। – Tim

उत्तर

5

ठीक है, क्योंकि आपने कहा है कि यह एकल-थ्रेड मामले पर सही तरीके से काम करता है, फिर "सामान्य" विधियां काम नहीं करतीं।आप निम्न कार्य करने की जरूरत है:

  • सभी चर कि समानांतर
  • में पहुँचा रहे हैं विशेष रूप से उन है कि संशोधित कर रहे हैं
  • एक साझा संसाधन पर हटाने के कॉल नहीं करते पर एक नज़र डालें
  • कि साझा संसाधनों पर काम सभी पुस्तकालय कार्यों पर एक नज़र डालें - देखें कि क्या उन्होंने आवंटन/आवंटन रद्द करने

नहीं करते यह उम्मीदवार हैं कि की सूची है डबल नष्ट कर दिया:

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]++; 

क्योंकि दो या अधिक प्रक्रियाओं त्रुटियों सरणी के लिए एक लिखने करने की कोशिश कर सकते हैं।

और बड़ा सलाह - थ्रेडेड मोड में कुछ भी (विशेष रूप से संशोधित!) तक पहुंचने की कोशिश न करें, यह फ़ंक्शन के लिए पैरामीटर नहीं है!

+0

धन्यवाद! साझा चर समानांतर क्षेत्र में नहीं हटाए जाते हैं। समांतर क्षेत्र के अंदर, केवल स्थानीय चर आवंटित और सौदा किए जाते हैं। – Tim

+0

@ टिम, आपकी समस्या भ्रष्टाचार हो सकती है, और दोबारा आवंटन नहीं - भ्रष्टाचार तब हो सकता है जब दो प्रोसेसर स्मृति में एक ही बिंदु पर लिखने का प्रयास करते हैं। –

+0

बिंदु के लिए धन्यवाद कि बाहर! यह समझ में आता है। थ्रेड के बीच साझा त्रुटियों में लेखन को सिंक्रनाइज़ कैसे करें? – Tim

2

आपकी ट्रेन विधि नई मेमोरी आवंटित करने से पहले _search_struct को हटा देती है। तो पहली बार ट्रेन कहा जाता है, इसे हटा दिया जाता है। ट्रेन करने के लिए उस कॉल से पहले आवंटित करने के लिए कोड है? आप जंक मेमोरी को हटाने की कोशिश कर सकते हैं (हालांकि हमारे पास बताने के लिए कोड नहीं है)।

+0

आप जानते हैं कि आप 'हटाएं 0;' सही कह सकते हैं? –

+0

हां, ट्रेन() पहले इसे हटा दें और फिर तुरंत आवंटित करें। – Tim

+0

@ कॉर्नेल, हाँ हटाएं 0 की अनुमति है। क्या आप जानते हैं कि यह पहली बार दिया गया कोड से हटा दिया गया है? @Tim। हाँ, यही वह है जो मैं भी कहता हूं। पहली बार ट्रेन कहा जाता है, _search_struct का मूल्य क्या है? –

4

अगर यह आपकी समस्या है मैं नहीं जानता, लेकिन:

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 के पहले आमंत्रण के लिए एक समस्या उत्पन्न करेगा।)

इसके अलावा, अनिवार्य: क्या आपको वास्तव में इन सभी मैन्युअल आवंटन और विध्वंस करने की आवश्यकता है? new[]/delete[] (जो लगभग हमेशा खराब होते हैं) के बजाय आप कम से कम std::vector का उपयोग क्यों नहीं कर रहे हैं?

+0

धन्यवाद। लेकिन एक शून्य सूचक हटा दें संभव है। इसे हटाने के बाद पॉइंटर को 0 को असाइन करना भी मेरी समस्या का समाधान नहीं करता है। – Tim

+0

@ टिम: ठीक है, 'एनयूएलएल हटाएं' एक नो-ऑप है (यही कारण है कि मैंने 'assert' का उपयोग करने का सुझाव दिया)। मैंने आपके बाद के संपादन को यह नहीं बताया कि यह एकल-थ्रेडेड परिदृश्य में नहीं हुआ था। – jamesdlin

संबंधित मुद्दे