Я работаю над параллельным кодом. В моей основной функции у меня есть цикл по времени, и в начале мне нужно скопировать класс с помощью оператора присваивания. Но каким-то образом на 4-м шаге на одном из процессоров возникает ошибка двойного освобождения или повреждения, а на других все в порядке; и ошибка на std::set и set::map. Ниже часть кода и основной цикл.
class Mesh
{
public:
const Mesh &operator=(const Mesh &mesh);
std::set<size_t> ghostSet;
std::map<size_t, size_t> localIndex;
}
Оператор присваивания:
const Mesh &operator=(const Mesh &mesh)
{
std::set<size_t>().swap(ghostSet); ///BUG here
std::map<size_t, size_t>().swap(localIndex); /// BUG sometimes here
for(auto const &it : mesh.localIndex)
localIndex[it.first] = it.second;
for(auto const &it : mesh.ghostSet)
ghostSet.insert(it);
return *this;
}
основная функция:
int main(int argc, char *argv[])
{
Mesh ms, ms_gh;
/// Some operation to ms;
for(size_t t = 0; t != 10; t++)
{
/// Some operation to ms;
ms_gh = ms;
/// Some operation to ms_gh;
}
}
#0 0x00002aaab2405207 in raise () from /lib64/libc.so.6
#1 0x00002aaab24068f8 in abort () from /lib64/libc.so.6
#2 0x00002aaab2447cc7 in __libc_message () from /lib64/libc.so.6
#3 0x00002aaab2450429 in _int_free () from /lib64/libc.so.6
#4 0x000000000041bfba in __gnu_cxx::new_allocator<std::_Rb_tree_node<unsigned long> >::deallocate (this=07fffffff8b50, __p=0x7131c0)
at /usr/include/c++/4.8.2/ext/new_allocator.h:110
#5 0x000000000041835c in std::_Rb_tree<unsigned long, unsigned long, std::_Identity<unsigned long>, std::ess<unsigned long>, std::allocator<unsigned long> >::_M_put_node (this=0x7fffffff8b50, __p=0x7131c0)
at /usr/include/c++/4.8.2/bits/stl_tree.h:374
#6 0x000000000041276e in std::_Rb_tree<unsigned long, unsigned long, std::_Identity<unsigned long>, std::ess<unsigned long>, std::allocator<unsigned long> >::_M_destroy_node (this=0x7fffffff8b50, __p=0x7131c0)
at /usr/include/c++/4.8.2/bits/stl_tree.h:422
#7 0x000000000040c8ad in std::_Rb_tree<unsigned long, unsigned long, std::_Identity<unsigned long>, std::ess<unsigned long>, std::allocator<unsigned long> >::_M_erase (this=0x7fffffff8b50, __x=0x7131c0)
at /usr/include/c++/4.8.2/bits/stl_tree.h:1127
#8 0x000000000040c88a in std::_Rb_tree<unsigned long, unsigned long, std::_Identity<unsigned long>, std::ess<unsigned long>, std::allocator<unsigned long> >::_M_erase (this=0x7fffffff8b50, __x=0x72f410)
at /usr/include/c++/4.8.2/bits/stl_tree.h:1125
#9 0x000000000040c88a in std::_Rb_tree<unsigned long, unsigned long, std::_Identity<unsigned long>, std::ess<unsigned long>, std::allocator<unsigned long> >::_M_erase (this=0x7fffffff8b50, __x=0x72b760)
at /usr/include/c++/4.8.2/bits/stl_tree.h:1125
#10 0x000000000040c88a in std::_Rb_tree<unsigned long, unsigned long, std::_Identity<unsigned long>, std::ess<unsigned long>, std::allocator<unsigned long> >::_M_erase (this=0x7fffffff8b50, __x=0x70fce0)
at /usr/include/c++/4.8.2/bits/stl_tree.h:1125
#11 0x00000000004080c4 in std::_Rb_tree<unsigned long, unsigned long, std::_Identity<unsigned long>, std::ess<unsigned long>, std::allocator<unsigned long> >::~_Rb_tree (this=0x7fffffff8b50, __in_chrg=<optimized ut>)
at /usr/include/c++/4.8.2/bits/stl_tree.h:671
#12 0x0000000000407bbc in std::set<unsigned long, std::less<unsigned long>, std::allocator<unsigned long> ::~set (this=0x7fffffff8b50,
__in_chrg=<optimized out>) at /usr/include/c++/4.8.2/bits/stl_set.h:90
#13 0x0000000000405003 in Mesh::operator= (this=0x7fffffffa8a0, mesh=...)
at mesh.cpp:73
#14 0x000000000048eb98 in DynamicMesh::reattach_ghost (mpi_comm=1140850688,
ms=..., cn=..., ms_gh=..., gh=..., cn_gh=..., ale=..., t=4)
at dynamicMesh.cpp:273
В этом случае трассировка #13 соответствует замене std::set.
Моя проблема в том, почему такая ошибка не появляется на первом временном шаге и почему она не появляется на всех процессорах. Более того, эта ошибка иногда возникает в строках, связанных с std::map.
Кроме того, на моем ноутбуке с macOS и Linux код можно успешно запустить; но это не работает на HPC.
std::set
, иstd::map
имеют операторы присваивания, я предлагаю вам использовать правило нуля и используйте оператор присваивания, сгенерированный компилятором по умолчанию. - person Some programmer dude   schedule 02.08.2018std::set
, иstd::map
не потокобезопасны. Вы синхронизируете доступ к ним? Так как вашoperator=
не показывает признаков синхронизации. - person Algirdas Preidžius   schedule 02.08.2018ghostSet.insert(it)
должно бытьghostSet.insert(*it)
. Тем не менее, вы можете заменить все тело операторной функции на{localIndex = mesh.localIndex; ghostSet = mesh.ghostSet; return *this;}
или (лучше) вообще не реализовывать оператор (поскольку эффект такой же, как у компилятора по умолчанию). - person Peter   schedule 02.08.2018=
, не нужно писать собственный (неэффективный) цикл копирования. На самом деле ваш класс может отказаться от пользовательского назначения и использовать значение по умолчанию, поскольку там нет неуправляемых указателей. Я сомневаюсь, что это и есть причины крушения, просто хочу иметь в виду. - person n. 1.8e9-where's-my-share m.   schedule 02.08.2018ghostSet.insert(it)
правильно, сбивает с толкуit
- это значение, а не итератор - person Alan Birtles   schedule 02.08.2018=
не сработало, давайте станцуем дождь вокруг этой линии. Нет, тоже не получится. - person n. 1.8e9-where's-my-share m.   schedule 02.08.2018std::set
илиstd::map
остаются действительными при вставке или перемещении элемента (например, при внутренней перебалансировке дерева), они становятся недействительными при удалении (что, конечно, происходит и при очистке). Поэтому, если вы держите итератор для установки или сопоставления где-либо перед назначением, убедитесь, что вы больше не используете его после этого! - person Aconcagua   schedule 02.08.2018