2010-06-06 7 views
1

pthread 프로그래밍이 처음이며 C++ & C 혼합 코드로 작업 할 때이 오류로 인해 중단되었습니다.전역 정적 부울 포인터로 인해 pthread를 사용하여 세그먼트 화 오류가 발생합니다.

내가 한 것은 C++ 코드로 작성된 스레드에서 c 코드를 호출하는 것입니다. 스레드에 사용 된 정적 부울 포인터 is_center이 있으며 스레드가 완료되면 빈 상태가됩니다.

그러나 프로그램이 c 함수로 처리 될 때마다 부울 포인터의 값이 변경되고 segmentation 오류가 free()로 인해 발생한다는 사실을 확인했습니다. 그리고 문제는 c 코드가 사용될 때만 발생합니다. C 코드를 제거하면 멀티 스레드 C++ 파트가 잘 작동합니다.

static bool *is_center; 

// omit other codes in between ... 

void streamCluster(PStream* stream) 
{ 
    // some code here ... 
    while(1){ 
     // some code here ... 
     is_center = (bool*)calloc(points.num,sizeof(bool)); 

     // start the parallel thread here. 
     // the c code is invoked in this function. 
     localSearch(&points,kmin, kmax,&kfinal); // parallel 

     free(is_center); 
    } 

그리고 (내 C 코드가 각 스레드에서 호출)는 다음과 같이 평행하게 사용하는 기능은 다음과 같습니다 :

void localSearch(Points* points, long kmin, long kmax, long* kfinal) { 
    pthread_barrier_t barrier; 
    pthread_t* threads = new pthread_t[nproc]; 
    pkmedian_arg_t* arg = new pkmedian_arg_t[nproc]; 

    pthread_barrier_init(&barrier,NULL,nproc); 

    for(int i = 0; i < nproc; i++) { 
      arg[i].points = points; 
      arg[i].kmin = kmin; 
      arg[i].kmax = kmax; 
      arg[i].pid = i; 
      arg[i].kfinal = kfinal; 
      arg[i].barrier = &barrier; 

      pthread_create(threads+i,NULL,localSearchSub,(void*)&arg[i]); 
    } 

    for (int i = 0; i < nproc; i++) { 
     pthread_join(threads[i],NULL); 
    } 

    delete[] threads; 
    delete[] arg; 
    pthread_barrier_destroy(&barrier); 
} 

마지막으로 함수 내 C 코드를 호출 다음과 같이

상세 코드는 :

void* localSearchSub(void* arg_) {                                       

    int eventSet = PAPI_NULL;                                                                                  
    begin_papi_thread(&eventSet);                                       

    pkmedian_arg_t* arg= (pkmedian_arg_t*)arg_;                                    
    pkmedian(arg->points,arg->kmin,arg->kmax,arg->kfinal,arg->pid,arg->barrier);                            

    end_papi_thread(&eventSet);                                                                                     

    return NULL;                                            
} 

그리고 GDB에서

, 나는 is_center에 대해 가지고 무엇을 :

Breakpoint 2, localSearchSub (arg_=0x600000000000bc40) at streamcluster.cpp:1711 
1711  end_papi_thread(&eventSet); 
(gdb) s 

Hardware watchpoint 1: is_center 

Old value = (bool *) 0x600000000000bba0 
New value = (bool *) 0xa93f3 
0x400000000000d8d1 in localSearchSub (arg_=0x600000000000bc40) at streamcluster.cpp:1711 
1711  end_papi_thread(&eventSet); 

의견이 있으십니까? 미리 감사드립니다!

코드에 대한 새로운 정보 : C 코드의 경우 PAPI 패키지를 사용하고 있습니다. 필자는 자신의 papi 래퍼를 작성하여 시스템 카운터를 초기화하고 읽습니다. 다음과 같이 코드는 다음과 같습니다

void begin_papi_thread(int* eventSet)                                      
{                                               
    int thread_id = pthread_self();                                      
    // Events                                            
    if (PAPI_create_eventset(eventSet)) {                                     
     PAPI_perror(return_value, error_string, PAPI_MAX_STR_LEN);                               
     printf("*** ERROR *** Failed to create event set for thread %d: %s\n.", thread_id, error_string);                     
    }                                              
    if((return_value = PAPI_add_events(*eventSet, event_code, event_num)) != PAPI_OK)                          
    {                                                                                                                                       
     printf("*** ERROR *** Failed to add event for thread %d: %d.\n", thread_id, return_value);                                                                   
    }                                              
    // Start counting                                          
    if ((return_value = PAPI_start(*eventSet)) != PAPI_OK) {                                                                            
     PAPI_perror(return_value, error_string, PAPI_MAX_STR_LEN);                                                                           
     printf("*** ERROR *** PAPI failed to start the event for thread %d: %s.\n", thread_id, error_string); 
    }                                                                                            
} 
void end_papi_thread(int* eventSet)                                      
{                                               
    int thread_id = pthread_self();                                      
    int i;                                             

    long long * count_values = (long long*)malloc(sizeof(long long) * event_num);                           
    if (PAPI_read(*eventSet, count_values) != PAPI_OK)                                  
     printf("*** ERROR *** Failed to load count values.\n");                               

    if (PAPI_stop(*eventSet, &dummy_values) != PAPI_OK) { 
     PAPI_perror(return_value, error_string, PAPI_MAX_STR_LEN); 
     printf("*** ERROR *** PAPI failed to stop the event for thread %d: %s.\n", thread_id, error_string); 
     return; 
    } 
    if(PAPI_cleanup_eventset(*eventSet) != PAPI_OK) 
     printf("*** ERROR *** Clean up failed for the thread %d.\n", thread_id);                           
} 
+0

코드가 충분하지 않습니다. 'localSearchSub()'에 무엇이 있습니까?당신은 watchpoints와 함께 올바른 길을 가고 있습니다. 'streamcluster.cpp : 1711' 주위의 코드를주의 깊게 살펴보고, 배열 오버/언더런, 모든 포인터 조작을 점검하십시오. 모든 단계를 명확하게 볼 수있는 지점까지 모든 것을 단순화하십시오. –

+0

문제는 내가 사용하는 C 코드에서 보이는 것 같습니다. PAPI API를 사용하여 각 스레드에서 하드웨어 카운터를 캡처하므로 위와 같이 래퍼를 작성하여 초기화하고 캡처를 시작합니다. 디버깅하는 동안'end_papi_thread'가 호출 된 후'is_center'의 주소가 변경된 다음'free (is_center)'에 의해 세그먼테이션 오류가 발생 함을 발견했습니다. papi 래퍼 코드를 제거한 후에 모든 것이 원활하게 작동합니다. 그래서 주소 업데이트로 인해 혼란 스러웠습니다. 'free (is_center)'는 내 생각에 메인 스레드의 컨텍스트에서 작동해야하지만 스레드 컨텍스트에있는 것 같습니다 ... – asksw0rder

답변

2

난 당신이 정말 당신의 문제를 이해하기에 충분한 코드를 게시 한 생각하지 않는다, 그러나 당신이 is_center 글로벌 선언 한 것으로 의심 보인다. 여러 스레드 (아마도 localSearchSub에 언급 된 작업자 스레드 함수)가 여러 곳에서 사용하고 있다고 가정합니다.

is_center을 여러 스레드에서 읽거나 쓰는 경우 pthread mutex으로 보호하고 싶을 것입니다. 스레드가 완료되면 "해제됩니다."라고 말하지만, 스레드가 nprocs 개임을 알고 있어야하며, 그들은 모두 is_center[points] bools의 배열로 작업하고있는 것처럼 보입니다. points != nproc이라면, 이것은 나쁜 것일 수 있습니다 [1]. 각 스레드는 자체 배열에서 작동해야하며 localSearch은 결과를 집계해야합니다.

xxx_papi_thread 기능

구글에 어떤 안타를하지 않기 때문에 나는 단지 그것의 상상할 수있는 자신의 ... 문제가 :)

[에있는 경우 우리는 당신을 도울 수있을 것 같지 1] : points == nproc이더라도 배열의 여러 요소에 여러 스레드 (컴파일러와 프로세서에 따라 다름)에서 쓰는 것이 반드시 필요한 것은 아닙니다. 안전하고, 뮤텍스를 사용하십시오.

또한 태그가 C++입니다. calloc 및 동적 배열 (new 사용)을 vector으로 바꿀 수 있습니까? 디버깅이 더 쉬워지고 결국 유지 보수가 더 쉬워집니다. 왜 코드의 독자를 싫어하고 처벌하고 싶습니까? ;)

+0

안녕하세요 스티븐, 제안 해 주셔서 감사합니다! 더 많은 코드를 게시했으며 다시 살펴 볼 수 있습니까? 현재 문제는 is_center의 전역 공유에 있어야한다고 생각합니다. 내 C 코드는 그것에 영향을 미치지 않는다고 생각 하나? 그것은 멀티 스레드에서 수 있습니다? – asksw0rder

+0

당신이 추가 한 코드가 그것을 사용하는 것처럼 보이지는 않겠지 만, 네가 맞을 거라 생각합니다. 그렇습니다. papi_thread 래퍼에는 명백한 실수가 없습니다 (그러나 PAPI 라이브러리에 익숙하지 않습니다) . 그러나 Google 코드에서'pkmedian' 코드를 발견했습니다. 컴파일 할 때'ENABLE_THREADS'를 정의합니까? 장벽을 사용하는 것이 필요합니다. http://code.google.com/p/ua-gpu/source/browse/trunk/rodinia/openmp/streamcluster/streamcluster_omp.cpp?spec=svn227&r=227#771 – Stephen

+0

예, 스레드가 사용 가능합니다. 필자가 오해하지 않으면 pthread_barrier가 쓰기 충돌을 격리시켜야합니까? 그런데 오류는 PAPI 래퍼를 사용할 때만 발생합니다 (다중 스레드는 래퍼없이 잘 작동합니다). 아마도 래퍼에 문제가있을 수 있습니까? – asksw0rder

관련 문제