OpenMP ***'...'中的错误:double free或corruption(fasttop):[address] ***

OpenMP ***'...'中的错误:double free或corruption(fasttop):[address] ***

问题描述:

我开始使用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'共享类。或者更好的是,在并行区域内声明它们并自动变为私有。 –

通过让多个线程在没有同步的情况下写入同一个变量,您可以在脚下自我拍摄。

你有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