グローバルな静的ブールポインターは、PTHREADを使用してセグメンテーション障害を引き起こします
-
24-10-2019 - |
質問
PTHREADプログラミングを新しくし、C ++&Cミックスコードで作業するときにこのエラーに固執しました。
私がやったことは、C ++コードによって作成されたスレッド内のCコードを呼び出すことです。静的ブールポインターがあります is_center
スレッドで使用されると、スレッドが終了すると無料になります。
ただし、プログラムがC関数に処理されるたびに、ブールポインターの値が変更され、セグメンテーション障害が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);
}
解決
私はあなたがあなたの問題を本当に理解するのに十分なコードを投稿したとは思わないが、あなたが宣言したのは疑わしいようだ is_center
グローバル。私はあなたがそれを複数の場所、おそらく複数のスレッドで使用していると思います(おそらく複数のスレッドでlocalSearchSub
それに言及しますが、これはあなたのワーカースレッド機能です)。
もしも is_center
複数のスレッドによって読まれたり書かれたりしているのですが、おそらくそれを保護したい pthread mutex. 。あなたはそれが「スレッドが終了したときに解放されている」と言いますが、あなたはあることに注意する必要があります nprocs
スレッド、そしてそれはすべての配列で作業しているように見えます is_center[points]
ブール。もしも points != nproc
, 、これは悪いことをする可能性があります[1]。各スレッドはおそらく独自の配列で動作するはずです。 localSearch
結果を集約する必要があります。
xxx_papi_thread
機能はGoogleでヒットを得ることができないので、問題がそこにある場合、私たちがあなたを助けることができる可能性は低いです:)
1]:場合でも points == nproc
, 、複数のスレッド(コンパイラとプロセッサに依存している)からの配列の異なる要素に書き込んでも、必ずしも問題ありません。安全で、ミューテックスを使用してください。
また、これにタグが付けられています C++
. 。交換できますか calloc
および動的配列(使用 new
) と vector
s?デバッグが簡単になる可能性があり、確かに維持しやすくなります。なぜあなたはあなたのコードの読者を罰したいのですか? ;)