2017-12-03 9 views
0

C++でopenMPを使い始めていますが、並列forループで問題があります削減と。以下の関数を実行すると、「* ./main.out」のエラー:ダブルフリーまたは破損(fasttop):0x00007fe2a00008c0 *」というエラーが表示されます。OpenMP ***のエラー '...':ダブルフリーまたは破損(fasttop):[アドレス] ***

***更新:ご協力いただきありがとうございます。私はあなたの提案(下記参照)に基づいて機能を編集し、正しく動作します。しかし、私はまだスピードアップを見ていないし、私がトップに走ったとき、%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

私がここでお勧めするのは、あなたがそこにいるクラスが3つのルールを守っているか、必要でないことを確認することです。 – user4581301

+0

C++では、 "3のルール"は "5のルール"になります。これは、 "移動割り当て"を追加する必要があるためです。これは、 "ec = ec_vec [i]"と "m = ec.mappings [r]と "移動コンストラクタ"です。 –

+2

あなたは大量の共有変数を持つ必要があります。 'm'、' gene_id'、 'cod_idx'、' d5'、 'd3'のように、いくつか挙げることができます。これらの変数に 'private'共有クラスを指定してください。あるいは、それを平行領域の内側に宣言すれば自動的にプライベートになります。 –

答えて

1

複数のスレッドが同じ変数に同期して書き込まれるようにすることで、足に自分を撃つことができます。

EquivClass ec;がパラレルセクションの外側にあるため、共有(スレッド間で共有)変数です。その後、パラレルセクションの内側にec = ec_vec[i];を入れます。これは、スレッドが共有変数に値をコピーすることを意味します。これはあなたに競争条件を与えるでしょう。このコピー割り当てはdeleteを呼び出すEquivClass::~EquivClassを呼び出し、newを呼び出すEquivClass::EquivClassを呼び出します。レースによっては、ダブルフリーエラーが発生します。

ecプライベート(スレッドにローカル)変数を修正します。 parallelセクションから、forのループの中にちょうどauto &ec = ec_vec[i];と宣言しないでください。次にecはプライベート変数になり、競合状態は存在しません。 &は参考になるので、コピーが必要でもありませんが、それは厳密には必要ではありません。

同様に、他の変数はすべて,であり、危険な競合状態になります。

+2

OpenMPの共有変数は単に「共有」と呼ばれます。 –

+0

@HristoIliev:説明をありがとう。私はそれを認識していますが、OPはOpenMPにとって新しく思われるので、これらの変数がどのように共有されているかを明確にしようとしました。 –

+1

残念ながら、OpenMPは "private"、 "threadprivate"、 "shared"の区別があるため、あなたの言い回し、特に "thread-local" *はあいまいです。あなたがプライベートを使用したい場合 - threadprivateではなく。私は初心者が必ずしも違いの複雑さを知っていなければならないと言っているわけではありませんが、最初から正しい用語を使用して後で混乱を避けるべきです。 – Zulan

関連する問題