__gnu_parallel::accumulate 出现意外的段错误
这真的让我很困惑,如果有人能帮助我,我将不胜感激。
(编辑:以为这是一个模板化问题,我错了)
我想使用 gnu 的并行累积算法添加以下类的多个副本(存储在 #include
中)
类故意不做太多事情,我想这不会是线程冲突问题吧?
template<class T>
class NaturalParameters
{
public:
typedef typename std::vector<T>::iterator iterator;
NaturalParameters()
: m_data(2) //vector with two zeros
{ }
typename std::vector<T>::const_iterator
begin() const
{
return m_data.begin();
}
typename std::vector<T>::const_iterator
end() const
{
return m_data.end();
}
NaturalParameters<T>&
operator+=(const NaturalParameters<T>& other)
{
//do something
return *this;
}
private:
std::vector<T> m_data;
};
template<class T>
inline
NaturalParameters<T>
operator+(const NaturalParameters<T>& a, const NaturalParameters<T>& b)
{
NaturalParameters<T> tmp = a;
return tmp+=b;
}
然后我运行它
int
main (int ac, char **av)
{
std::vector<NaturalParameters<double> > NP(1000);
NaturalParameters<double> init;
//the following segfaults
NaturalParameters<double> NP2 = __gnu_parallel::accumulate(NP.begin(), NP.end(), init );
//The following runs fine
//NaturalParameters<double> NP2 = std::accumulate(NP.begin(), NP.end(), init );
}
这真的让我很困惑 - 我不知道问题是什么。 我正在使用 g++ 4.4.5 并使用 g++ gnu_parallel.cpp -g -fopenmp
编辑:
请注意,这有效:(999 个元素而不是 1000 个)
for(size_t i=0;i<1000;++i){
std::vector<NaturalParameters> ChildrenNP(999);
NaturalParameters<double> init;
NaturalParameters<double> NP = __gnu_parallel::accumulate(ChildrenNP.begin(), ChildrenNP.end(), init );
//NaturalParameters<double> NP = std::accumulate(ChildrenNP.begin(), ChildrenNP.end(), init );
}
回溯是:
Program received signal SIGSEGV, Segmentation fault.
__libc_free (mem=0x12af1) at malloc.c:3709
3709 malloc.c: No such file or directory.
in malloc.c
(gdb) backtrace
#0 __libc_free (mem=0x12af1) at malloc.c:3709
#1 0x00000000004024f8 in __gnu_cxx::new_allocator<double>::deallocate (this=0x614518, __p=0x12af1) at /usr/include/c++/4.4/ext/new_allocator.h:95
#2 0x0000000000401f0a in std::_Vector_base<double, std::allocator<double> >::_M_deallocate (this=0x614518, __p=0x12af1, __n=18446744073709542049) at /usr/include/c++/4.4/bits/stl_vector.h:146
#3 0x00000000004017b9 in std::_Vector_base<double, std::allocator<double> >::~_Vector_base (this=0x614518, __in_chrg=<value optimized out>) at /usr/include/c++/4.4/bits/stl_vector.h:132
#4 0x00000000004013b9 in std::vector<double, std::allocator<double> >::~vector (this=0x614518, __in_chrg=<value optimized out>) at /usr/include/c++/4.4/bits/stl_vector.h:313
#5 0x00000000004012b8 in NaturalParameters<double>::~NaturalParameters (this=0x614518, __in_chrg=<value optimized out>) at gnu_parallel.cpp:10
#6 0x00000000004023e7 in __gnu_parallel::for_each_template_random_access_ed<__gnu_cxx::__normal_iterator<NaturalParameters<double>*, std::vector<NaturalParameters<double>, std::allocator<NaturalParameters<double> > > >, __gnu_parallel::nothing, __gnu_parallel::accumulate_selector<__gnu_cxx::__normal_iterator<NaturalParameters<double>*, std::vector<NaturalParameters<double>, std::allocator<NaturalParameters<double> > > > >, __gnu_parallel::accumulate_binop_reduct<__gnu_parallel::plus<NaturalParameters<double>, NaturalParameters<double> > >, NaturalParameters<double> > (begin=..., end=..., o=..., f=..., r=...,
base=..., output=..., bound=-1) at /usr/include/c++/4.4/parallel/par_loop.h:127
#7 0x0000000000401d70 in std::__parallel::accumulate_switch<__gnu_cxx::__normal_iterator<NaturalParameters<double>*, std::vector<NaturalParameters<double>, std::allocator<NaturalParameters<double> > > >, NaturalParameters<double>, __gnu_parallel::plus<NaturalParameters<double>, NaturalParameters<double> > > (begin=..., end=..., init=..., binary_op=..., parallelism_tag=__gnu_parallel::parallel_unbalanced)
at /usr/include/c++/4.4/parallel/numeric:99
#8 0x0000000000401655 in std::__parallel::accumulate<__gnu_cxx::__normal_iterator<NaturalParameters<double>*, std::vector<NaturalParameters<double>, std::allocator<NaturalParameters<double> > > >, NaturalParameters<double> > (begin=..., end=..., init=...) at /usr/include/c++/4.4/parallel/numeric:139
#9 0x0000000000400e2c in main (ac=1, av=0x7fffffffe188) at gnu_parallel.cpp:59
This is really confusing me, I would appreciate if anyone could help me out.
(EDIT: thought it was a templated problem, I was mistaken with this)
I want to add multiple copies of the following class with gnu's parallelised accumulate algorithm (stored in #include <parallel/numeric>
)
The class deliberately doesn't do much, I don't think this is a thread collision problem?
template<class T>
class NaturalParameters
{
public:
typedef typename std::vector<T>::iterator iterator;
NaturalParameters()
: m_data(2) //vector with two zeros
{ }
typename std::vector<T>::const_iterator
begin() const
{
return m_data.begin();
}
typename std::vector<T>::const_iterator
end() const
{
return m_data.end();
}
NaturalParameters<T>&
operator+=(const NaturalParameters<T>& other)
{
//do something
return *this;
}
private:
std::vector<T> m_data;
};
template<class T>
inline
NaturalParameters<T>
operator+(const NaturalParameters<T>& a, const NaturalParameters<T>& b)
{
NaturalParameters<T> tmp = a;
return tmp+=b;
}
I then run it
int
main (int ac, char **av)
{
std::vector<NaturalParameters<double> > NP(1000);
NaturalParameters<double> init;
//the following segfaults
NaturalParameters<double> NP2 = __gnu_parallel::accumulate(NP.begin(), NP.end(), init );
//The following runs fine
//NaturalParameters<double> NP2 = std::accumulate(NP.begin(), NP.end(), init );
}
This really confuses me - I have no idea what the problem is.
I'm using g++ 4.4.5 and compiling with g++ gnu_parallel.cpp -g -fopenmp
EDIT:
Note that this works: (999 elements rather than 1000)
for(size_t i=0;i<1000;++i){
std::vector<NaturalParameters> ChildrenNP(999);
NaturalParameters<double> init;
NaturalParameters<double> NP = __gnu_parallel::accumulate(ChildrenNP.begin(), ChildrenNP.end(), init );
//NaturalParameters<double> NP = std::accumulate(ChildrenNP.begin(), ChildrenNP.end(), init );
}
The backtrace is:
Program received signal SIGSEGV, Segmentation fault.
__libc_free (mem=0x12af1) at malloc.c:3709
3709 malloc.c: No such file or directory.
in malloc.c
(gdb) backtrace
#0 __libc_free (mem=0x12af1) at malloc.c:3709
#1 0x00000000004024f8 in __gnu_cxx::new_allocator<double>::deallocate (this=0x614518, __p=0x12af1) at /usr/include/c++/4.4/ext/new_allocator.h:95
#2 0x0000000000401f0a in std::_Vector_base<double, std::allocator<double> >::_M_deallocate (this=0x614518, __p=0x12af1, __n=18446744073709542049) at /usr/include/c++/4.4/bits/stl_vector.h:146
#3 0x00000000004017b9 in std::_Vector_base<double, std::allocator<double> >::~_Vector_base (this=0x614518, __in_chrg=<value optimized out>) at /usr/include/c++/4.4/bits/stl_vector.h:132
#4 0x00000000004013b9 in std::vector<double, std::allocator<double> >::~vector (this=0x614518, __in_chrg=<value optimized out>) at /usr/include/c++/4.4/bits/stl_vector.h:313
#5 0x00000000004012b8 in NaturalParameters<double>::~NaturalParameters (this=0x614518, __in_chrg=<value optimized out>) at gnu_parallel.cpp:10
#6 0x00000000004023e7 in __gnu_parallel::for_each_template_random_access_ed<__gnu_cxx::__normal_iterator<NaturalParameters<double>*, std::vector<NaturalParameters<double>, std::allocator<NaturalParameters<double> > > >, __gnu_parallel::nothing, __gnu_parallel::accumulate_selector<__gnu_cxx::__normal_iterator<NaturalParameters<double>*, std::vector<NaturalParameters<double>, std::allocator<NaturalParameters<double> > > > >, __gnu_parallel::accumulate_binop_reduct<__gnu_parallel::plus<NaturalParameters<double>, NaturalParameters<double> > >, NaturalParameters<double> > (begin=..., end=..., o=..., f=..., r=...,
base=..., output=..., bound=-1) at /usr/include/c++/4.4/parallel/par_loop.h:127
#7 0x0000000000401d70 in std::__parallel::accumulate_switch<__gnu_cxx::__normal_iterator<NaturalParameters<double>*, std::vector<NaturalParameters<double>, std::allocator<NaturalParameters<double> > > >, NaturalParameters<double>, __gnu_parallel::plus<NaturalParameters<double>, NaturalParameters<double> > > (begin=..., end=..., init=..., binary_op=..., parallelism_tag=__gnu_parallel::parallel_unbalanced)
at /usr/include/c++/4.4/parallel/numeric:99
#8 0x0000000000401655 in std::__parallel::accumulate<__gnu_cxx::__normal_iterator<NaturalParameters<double>*, std::vector<NaturalParameters<double>, std::allocator<NaturalParameters<double> > > >, NaturalParameters<double> > (begin=..., end=..., init=...) at /usr/include/c++/4.4/parallel/numeric:139
#9 0x0000000000400e2c in main (ac=1, av=0x7fffffffe188) at gnu_parallel.cpp:59
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这绝对看起来像是 libstdc++ 中的一个 bug:
/usr/include/c++/4.4/parallel/par_loop.h:87
但第 127 行用 _ 删除了它
显然,thread_results 的构造在一阶段进行了优化,但是删除声明从未更新以反映这一点。与仅更新数组(new Result[num_threads])相比,优化更有意义,因为它避免了构造元素。_
修复该问题以
消除错误。您需要将此报告给 gnu 开发人员。
您可能仍然对 std::__cxx1998::vector::operator= 的线程安全性存在一些残留问题。你可以通过使用 valgrind 明白我的意思。然而,valgrind 完全有可能在那里报告错误的阳性结果。
我只是以相反的方式进行了测试:当使用
new Result[num_threads]
和delete[]
(而不是 GNU 源代码中的优化版本)时,您将得到一个干净的结果valgrind 一路奔跑。我很确定这将是误报,但我肯定会在您报告错误时向 GNU 开发人员提及它。This definitely looks like a bug in libstdc++:
/usr/include/c++/4.4/parallel/par_loop.h:87
But line 127 deletes it with
_Apparently, the construction of thread_results was optimized at one stage, but the deletion statement was never updated to reflect this. The optimization makes sense over just newing up the array (new Result[num_threads]) because it avoids constructing the elements._
Fixing that to
removes the bug. You will want to report this to the gnu devs.
You might still have some residu problems with the threadsafety of std::__cxx1998::vector::operator=. You can see what I mean by using valgrind. However, it is entirely possible that valgrind reports a fasle positive there.
I just tested the other way around: when using
new Result[num_threads]
withdelete[]
(instead of the optimized version in the GNU source) you'll get a clean valgrind run all the way. I'm pretty sure this will be a false positive, but I'd sure mention it to the GNU devs while you report the bug.嗯,这就是线程。穿线很难。即使使用 gomp/并行扩展。尝试 helgrind (
valgrind --tool=helgrind ./t
)。输出太大了...所以不允许我将其粘贴到这里:)Well, this is threading. Threading is hard. Even with gomp/parallel extensions. Try helgrind (
valgrind --tool=helgrind ./t
). The output is so large... SO won't let me paste it in here :)