J. R.
J. R.

Reputation: 13

OpenMP *** Error in '...': double free or corruption (fasttop): [address] ***

I'm getting started with openMP in C++, and I'm having trouble with a parallel for loop with reduction. When I run the function below, I get the error: "* Error in `./main.out': double free or corruption (fasttop): 0x00007fe2a00008c0 *".

***UPDATE: Thank you all for your help! I edited the function based on your suggestions (see below), and it runs correctly. But I'm still not seeing any speedup, and when I run top, the %CPU field never goes over 100%. Any thoughts?

...
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;
}

Upvotes: 0

Views: 1649

Answers (1)

Martin Ueding
Martin Ueding

Reputation: 8719

You shoot yourself in the foot by letting multiple threads write to the same variable without synchronization.

You have EquivClass ec; outside of the parallel section, so it is a shared (shared among threads) variable. Then you do ec = ec_vec[i]; inside the parallel section. This means that threads copy the value to a shared variable. This will give you race conditions. This copy-assignment will call EquivClass::~EquivClass, which might call delete, and then it will call EquivClass::EquivClass which might call new. Depending on the race, this will result in double free errors.

To fix this part, make ec a private (local to the thread) variable. Do not declare it out of the parallel section but just within the for loop as auto &ec = ec_vec[i];. Then ec will the a private variable, and there is no race condition. The & will make it a reference, so there is not even the need for a copy, but that is not strictly necessary.

Similarly all the other variables that you have there are shared and will give you dangerous race conditions.

Upvotes: 1

Related Questions