2011-04-24 2 views
1

이것은 정말 혼란 스럽습니다. 누군가 나를 도울 수 있다면 감사 할 것입니다.예기치 않은 segfault와 __gnu_parallel :: accumulate

(편집 : 나는이와 잘못된 템플릿 화 문제였다 생각) 나는 (#include <parallel/numeric>에 저장) GNU의 parallelised 축적 알고리즘

클래스에 다음 클래스의 사본을 여러 개 추가 할

고의적으로 많이하지 않는다. 나는 스레드 콜리 전 문제라고 생각하지 않는다.

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 
+0

GNU 병렬 확장의 일부와 함께 segfault를 재생산 할 수 있습니다. 실제로 구현에 버그가 있다고 의심됩니다. –

+0

@sehe, 해당 참조가 없습니까? 그 사본? – Tom

+0

DoSomething을'operator + ='에 게시해야합니다. – Puppy

답변

3

못하게 :

/usr/include/c++/4.4/parallel/par_loop합니다. 시간 : 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의 건설은 한 단계에서 최적화되었지만 삭제 문 WA 이을 반영하도록 업데이트되지 않았습니다. 단지 배열 (새 결과 [NUM_THREADS]을)를 newing 이상이

delete thread_results; 

에하면 버그를 제거한다는 고정 elements._에게

를 구성하는 것을 피한다 때문에 최적화는 의미가 있습니다. 이것을 gnu devs에게보고하고 싶을 것이다.


는 여전히 표준 : __ cxx1998 : 벡터 :: 연산자 =의 threadsafety 일부 residu 문제가있을 수 있습니다. valgrind를 사용하면 무슨 뜻인지 알 수 있습니다. 그러나 valgrind가 거기에 긍정적 인 결과를보고하는 것은 전적으로 가능합니다.

난 그냥 다른 방법으로 테스트했습니다 : delete[] (GNU 소스의 최적화 된 버전 대신) new Result[num_threads]을 사용하면 깨끗한 valgrind가 항상 실행됩니다.나는 이것이 거짓 긍정이 될 것이라 확신하지만, 버그를보고하는 동안 확실히 GNU devs에 언급 할 것입니다. .

+0

잔여 valgrind 문제점을 좁히십시오 – sehe

+0

+1 당신은 어떻게 그것을 찾아 냈습니까? 저는 지금 버그 보고서를 작성하는 것에 매우 감명 받았습니다. – Tom

+0

아우, 광산 여기에 있습니다 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48750 – sehe

1

음, 이것은 스레딩입니다. 스레딩은 어렵습니다. gomp/parallel 확장을 사용해도. helgrind (valgrind --tool=helgrind ./t)를 시도하십시오. 출력은 너무 커서 ... 그래서 내가 여기에 붙여 넣습니다 :)이 확실히 된 libstdc 버그 ++과 같은

+0

이것은 깔끔한 도구입니다. helgrind 옵션을 보지 못했습니다. 전에. 감사! – Tom