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);
}
코드가 충분하지 않습니다. 'localSearchSub()'에 무엇이 있습니까?당신은 watchpoints와 함께 올바른 길을 가고 있습니다. 'streamcluster.cpp : 1711' 주위의 코드를주의 깊게 살펴보고, 배열 오버/언더런, 모든 포인터 조작을 점검하십시오. 모든 단계를 명확하게 볼 수있는 지점까지 모든 것을 단순화하십시오. –
문제는 내가 사용하는 C 코드에서 보이는 것 같습니다. PAPI API를 사용하여 각 스레드에서 하드웨어 카운터를 캡처하므로 위와 같이 래퍼를 작성하여 초기화하고 캡처를 시작합니다. 디버깅하는 동안'end_papi_thread'가 호출 된 후'is_center'의 주소가 변경된 다음'free (is_center)'에 의해 세그먼테이션 오류가 발생 함을 발견했습니다. papi 래퍼 코드를 제거한 후에 모든 것이 원활하게 작동합니다. 그래서 주소 업데이트로 인해 혼란 스러웠습니다. 'free (is_center)'는 내 생각에 메인 스레드의 컨텍스트에서 작동해야하지만 스레드 컨텍스트에있는 것 같습니다 ... – asksw0rder