2010-06-06 67 views
1

pthread編程的新手,並且在C++ & C混合代碼上工作時出現此錯誤。全局靜態布爾指針使用pthread導致段錯誤

我所做的就是調用由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);                           
} 
+0

代碼不足。 'localSearchSub()'中有什麼?儘管如此,你仍然處於正確的軌道上。仔細查看'streamcluster.cpp:1711'周圍的代碼,檢查數組是否超出/低於運行,任何指針操作。儘量簡化所有步驟清晰可見的步驟。 – 2010-06-06 01:43:44

+0

問題出現在我使用的c代碼上。我使用PAPI API來捕獲每個線程中的硬件計數器,因此我編寫了一個如上所述的包裝來初始化它並開始捕獲。 我發現在我的調試過程中,調用'end_papi_thread'後'is_center'的地址被改變了,然後分段錯誤被'free(is_center)'觸發了。刪除我的papi包裝代碼後,一切正常。 所以我很困惑地址的更新。 '免費(is_center)'應該在主線程的上下文中工作在我看來,但它似乎在線程上下文... – asksw0rder 2010-06-06 03:38:34

回答

2

我不認爲你已經發布足夠的代碼,以真正瞭解你的問題,但它看起來可疑,你已經宣佈is_center全球。我假設你在多個地方使用它,可能是由多個線程(localSearchSub提到它,這是你的工作線程函數)。

如果is_center正在被多個線程讀取或寫入,您可能需要使用pthread mutex來保護它。你說它在線程結束時「釋放」,但是你應該知道線程有nprocs,看起來他們都在使用一組is_center[points]布爾。如果points != nproc,這可能是一件壞事[1]。每個線程應該可以在自己的數組上工作,並且localSearch應該彙總結果。

xxx_papi_thread功能沒有得到谷歌上的任何命中,所以我只能想象這是你自己......不太可能,我們將能夠幫助你,如果問題出在那裏:)

[ 1]:即使points == nproc,從多個線程(它依賴於編譯器和處理器)寫入數組的不同元素也不一定正確。保證安全,使用互斥鎖。

此外,這被標記爲C++。你可以用vector s替換calloc和動態數組(使用new)嗎?它最終可能更容易調試,並且最終更容易維護。你爲什麼討厭並想要懲罰你的代碼的讀者? ;)

+0

嗨斯蒂芬,感謝您的建議!我發佈了更多的代碼,也許你可以再看看他們? 目前我認爲這個問題應該是全球共享'is_center'。我認爲我的c代碼對它沒有任何影響,對吧?它可能來自多線程? – asksw0rder 2010-06-06 02:30:26

+0

我猜是的,雖然你添加的代碼似乎沒有使用它...所以,我不知道:) papi_thread包裝沒有任何明顯的錯誤(但我不熟悉PAPI lib) 。但是,我在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 2010-06-06 02:41:07

+0

是的,線程已啓用。如果我沒有誤解它,pthread_barrier應該能夠隔離寫入衝突嗎?順便說一下,錯誤只發生在我使用PAPI包裝器時(多線程可以很好地工作而沒有包裝器)......可能還有包裝器有問題嗎? – asksw0rder 2010-06-06 03:20:11