OpenMP *** "..."中的错误:双重释放或损坏(快速顶部):[地址] ***



我在C++开始使用openMP,并且在使用带有缩减的并行for循环时遇到了问题。当我运行下面的函数时,我收到错误:">*错误在'./main.out':双重释放或损坏(快速顶部):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;
}

通过让多个线程写入同一变量而不同步,您搬起石头砸自己的脚。

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

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

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

最新更新