【问题标题】:OpenMP *** Error in '...': double free or corruption (fasttop): [address] ***OpenMP ***“...”中的错误:双重释放或损坏(fasttop):[地址] ***
【发布时间】:2017-12-03 19:00:48
【问题描述】:

我开始使用 C++ 中的 openMP,但在使用缩减的并行 for 循环时遇到了问题。当我运行下面的函数时,我收到错误:“* Error in `./main.out': double free or corruption (fasttop): 0x00007fe2a00008c0 *”。

***更新:谢谢大家的帮助!我根据您的建议编辑了该功能(见下文),它运行正常。但是我仍然没有看到任何加速,当我运行 top 时,%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;
}

【问题讨论】:

  • 我能建议的最好的办法是确保你在那里的课程要么遵守三法则,要么不需要。在此处复制:ec = ec_vec[i];m = ec.mappings[r];
  • 在 C++ 中,“三规则”变成了“五规则”,因为必须添加“移动赋值”和“移动构造函数”。
  • 您有大量必须是私有的共享变量。 mgene_idcod_idxd5d3,仅举几例。确保为这些变量提供private 共享类。或者更好的是,在并行区域内声明它们,它们会自动变为私有。
  • 谢谢大家的帮助!

标签: c++ parallel-processing openmp


【解决方案1】:

如果让多个线程在不同步的情况下写入同一个变量,你会自取其辱。

您在并行部分之外有EquivClass ec;,因此它是一个共享(线程间共享)变量。然后你在并行部分执行ec = ec_vec[i];。这意味着线程将值复制到共享变量。这将为您提供比赛条件。此复制分配将调用EquivClass::~EquivClass,它可能调用delete,然后它将调用EquivClass::EquivClass,它可能调用new。根据比赛,这将导致双重免费错误。

要修复此部分,请将ec 设为私有(线程本地)变量。不要在parallel 部分之外声明它,而是在for 循环内声明为auto &amp;ec = ec_vec[i];。然后ec 将是一个私有变量,并且没有竞争条件。 &amp; 会将其作为参考,因此甚至不需要副本,但这并不是绝对必要的。

同样地,您拥有的所有其他变量都是共享的,并且会给您带来危险的竞争条件。

【讨论】:

  • OpenMP 中的共享变量简称为“shared”。
  • @HristoIliev:感谢您的澄清。我知道这一点,但 OP 对 OpenMP 来说似乎是新的,因此我试图更清楚地说明这些变量之间共享的内容。
  • 很遗憾,您的措辞,特别是 “thread-local” 是模棱两可的,因为 OpenMP 在“private”、“thread-private”和“shared”之间有区别。如果您想使用私有 - 而不是 threadprivate。我并不是说初学者必须知道这些差异的复杂性,但是您应该从一开始就使用正确的术语以避免以后混淆。
  • 看来我必须再次阅读这些内容。感谢您的提示,然后我会更新我的答案。
猜你喜欢
  • 1970-01-01
  • 2021-12-04
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多