2010-06-06 64 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