2017-12-03 241 views
0

我開始使用C++中的openMP,並且遇到了並行for循環與減少。當我運行下面的函數時,出現錯誤:「* ./main.out'中的錯誤:雙重空閒或損壞(fasttop):0x00007fe2a00008c0 *」。OpenMP ***'...'中的錯誤:double free或corruption(fasttop):[address] ***

***更新:謝謝大家的幫助!我根據您的建議編輯了該功能(請參閱下文),並且它可以正常運行。但是我仍然沒有看到任何加速,並且當我運行頂部時,%CPU字段永遠不會超過100%。有什麼想法嗎?

... 
const int NUM_THREADS = 10; 
... 
double Parameters::get_log_likelihood(
     const vector<EquivClass> & ec_vec, 
     const vector<Gene> & genes_vec, 
     const unordered_map<int,double> & delta5, 
     const unordered_map<int,double> & delta3, 
     const unordered_map<string,double> & beta5, 
     const unordered_map<string,double> & beta3) { 
    // Init vars. 
    vector<vector<double>> denoms5, denoms3; 
    double log_likelihood, mapping_ll; 
    EquivClass ec; 
    Mapping m; 
    int gene_id, cod_idx, d5, d3; 
    string b5, b3; 

    denoms5 = get_all_5_denominators(genes_vec, delta5, beta5); 
    denoms3 = get_all_3_denominators(genes_vec, delta3, beta3); 
    log_likelihood = 0; 

    #pragma omp parallel for reduction(+ : log_likelihood) 
    for (int i=0; i<ec_vec.size(); i++) { 
     ec = ec_vec[i]; 
     for (int r=0; r<ec.num_mappings; r++) { 
      m = ec.mappings[r]; 
      gene_id = m.gene_id; 
      cod_idx = m.cod_idx; 
      d5 = m.d5; 
      d3 = m.d3; 
      b5 = get_b5(genes_vec[gene_id], cod_idx, d5); 
      b3 = get_b3(genes_vec[gene_id], cod_idx, d3); 
      mapping_ll = ec.exp_cts[r] * (
       log(rho.at(gene_id)) + log(pi.at(gene_id).at(cod_idx)) + 
       log(delta5.at(d5)) + log(beta5.at(b5)) + 
       log(delta3.at(d3)) + log(beta3.at(b3)) - 
       log(denoms5.at(gene_id).at(cod_idx)) - 
       log(denoms3.at(gene_id).at(cod_idx))); 
      if (!isnan(mapping_ll)) { 
       log_likelihood += mapping_ll; 
      } else { 
       ; 
      } 
     } 
    } 
    return log_likelihood; 
} 

************** 
*** UPDATED 
************** 
double Parameters::get_log_likelihood(
     const vector<EquivClass> & ec_vec, 
     const vector<Gene> & genes_vec, 
     const unordered_map<int,double> & delta5, 
     const unordered_map<int,double> & delta3, 
     const unordered_map<string,double> & beta5, 
     const unordered_map<string,double> & beta3) { 
    // Init vars. 
    vector<vector<double>> denoms5, denoms3; 
    double log_likelihood = 0; 

    denoms5 = get_all_5_denominators(genes_vec, delta5, beta5); 
    denoms3 = get_all_3_denominators(genes_vec, delta3, beta3); 

    #pragma omp parallel for reduction(+:log_likelihood) 
    for (int i=0; i<ec_vec.size(); i++) { 
     const EquivClass & ec = ec_vec[i]; 
     for (int r=0; r<ec.num_mappings; r++) { 
      const Mapping & m = ec.mappings[r]; 
      string b5 = get_b5(genes_vec[m.gene_id], m.cod_idx, m.d5); 
      string b3 = get_b3(genes_vec[m.gene_id], m.cod_idx, m.d3); 
      double mapping_ll = ec.exp_cts[r] * (
       log(rho[m.gene_id]) + log(pi[m.gene_id][m.cod_idx]) + 
       log(delta5.at(m.d5)) + log(beta5.at(b5)) + 
       log(delta3.at(m.d3)) + log(beta3.at(b3)) - 
       log(denoms5[m.gene_id][m.cod_idx]) - 
       log(denoms3[m.gene_id][m.cod_idx])); 
      if (!isnan(mapping_ll)) { 
       log_likelihood += mapping_ll; 
      } else { 
       ; 
      } 
     } 
    } 
    return log_likelihood; 
} 

int main (int argv, char * argc []) { 
    ... 
    omp_set_num_threads(NUM_THREADS); 
    Parameters params(...) 
    params.get_log_likelihood(...); 
    ... 
    return 0; 
} 
+1

我在這裏可以建議的最好的方法是確保你在那裏得到的課程要麼遵守三項規則,要麼不需要。在這裏複製:'ec = ec_vec [i];'和'm = ec.mappings [r];' – user4581301

+0

使用C++時,「三個規則」變成了「五個規則」,因爲必須添加一個「移動任務」和「移動構造函數」。 –

+2

你有很多共享變量必須是私有的。 'm','gene_id','cod_idx','d5','d3',等等。確保你賦予這些變量'private'共享類。或者更好的是,在並行區域內聲明它們並自動變爲私有。 –

回答

1

通過讓多個線程在沒有同步的情況下寫入同一個變量,您可以在腳下自我拍攝。

你有EquivClass ec;以外的並行部分,所以它是一個共享(線程間共享)變量。然後你在並行部分內部做ec = ec_vec[i];。這意味着線程將該值複製到共享變量。這會給你比賽條件。該副本分配將呼叫EquivClass::~EquivClass,其可能會呼叫delete,然後它將呼叫EquivClass::EquivClass,這可能會呼叫new。根據種族的不同,這會導致雙倍的免費錯誤。

要修復此部分,請將ec設爲私有(局部於該線程)變量。不要將其聲明爲parallel部分,而是在for循環內作爲auto &ec = ec_vec[i];。然後ec將是一個私有變量,並且沒有競爭條件。 &將作爲參考,所以甚至不需要複製,但這不是絕對必要的。

同樣,你在那裏的所有其他變量是共享,並會給你危險的競爭條件。

+2

OpenMP中的共享變量簡稱爲「共享」。 –

+0

@HristoIliev:謝謝你的澄清。我意識到這一點,但OP似乎對OpenMP來說是新的,因此我試圖更加清楚這些變量之間是如何共享的。 –

+1

不幸的是,您的措辭,特別是*「線程本地」*是不明確的,因爲OpenMP在「private」,「threadprivate」和「shared」之間存在區別。在這種情況下,你想使用私有 - 而不是threadprivate。我並不是說初學者必須知道這些差異的複雜性,但是您應該從一開始就使用正確的術語,以避免以後出現混淆。 – Zulan

相關問題