1

这真的让我很困惑,如果有人能帮助我,我将不胜感激。

(编辑:认为这是一个模板问题,我错了)

我想用 gnu 的并行累积算法(存储在#include <parallel/numeric>)添加以下类的多个副本

类故意不做太多,我不觉得这是线程冲突的问题吗?

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
4

2 回答 2

3

这绝对看起来像 libstdc++ 中的一个错误:

/usr/include/c++/4.4/parallel/par_loop.h:87

#   pragma omp single
      {
        num_threads = omp_get_num_threads();
        thread_results = static_cast<Result*>(
                            ::operator new(num_threads * sizeof(Result)));
        constructed = new bool[num_threads];
      }

但是第 127 行删除了它

delete[] thread_results;

_显然,thread_results 的构造在某一阶段进行了优化,但删除语句从未更新以反映这一点。优化对仅更新数组(new Result[num_threads])有意义,因为它避免了构造元素。_

将其修复为

delete thread_results;

删除错误。您需要将此报告给 gnu 开发人员。


std::__cxx1998::vector::operator= 的线程安全性可能仍然存在一些残留问题。您可以通过使用 valgrind 了解我的意思。然而,valgrind 完全有可能在那里报告假阳性。

我只是测试了另一种方式:当使用new Result[num_threads]with delete[](而不是 GNU 源代码中的优化版本)时,您将一直运行干净的 valgrind。我很确定这将是一个误报,但我肯定会在您报告错误时向 GNU 开发人员提及它

于 2011-04-24T11:19:24.707 回答
1

嗯,这是线程。线程很难。即使使用 gomp/并行扩展。试试 helgrind ( valgrind --tool=helgrind ./t)。输出是如此之大......所以不会让我把它粘贴在这里:)

于 2011-04-24T10:19:39.127 回答