2012-07-26 86 views
1

无法理解段错误的情况。pthread_join()上的分段错误

int main() 
{ 
    int val; 
    pthread_t thread; 
........................... 
    pthread_join(thread,(void **) &val); 
    printf("Val=%d",val); 
//and here sometimes come segmentation 
//fault and other times i get correct val value 

........................... 
} 

void *Do(void *) 
{ 
    int retval=4; 
............... 
    pthread_exit((void *) retval); 
} 

如果我正确,了pthread_exit()存储ADDRES(其值为4)到由(& VAL)指针,这意味着VAL = 4在pthread_join后()指出变量。但是,如果我多次启动程序,就会得到正确的val值(即4)和不同启动时的分段错误。 (顺便说一句,在Do函数中使用指针和动态分配的正确方式时,结果相同)。

请帮助我。 预先感谢您。

+0

你拿出太多了。在添加更多内容时,请修复缩进。 – Wug 2012-07-26 18:42:38

回答

0

我能想到的唯一的事实是,你正在返回函数* Do的局部变量的地址。局部变量存储在为该函数分配的堆栈帧中。在线程终止后,您将返回一个指向无效位置的指针。

参见:
http://man7.org/linux/man-pages/man3/pthread_exit.3.html

哪里是说:

的价值指向RETVAL不宜设呼叫 线程的堆栈,因为该堆栈的内容 线程终止后未定义。

0
pthread_exit((void *) retval); 

这需要一个整数(具有未确定的大小),并将其与潜在的不同尺寸投射到一个指针。我会说,大多数情况下,sizeof(void *)> = sizeof(int)都可以。

pthread_join(thread,(void **) &val); 

这个调用只有在sizeof(int)== sizeof(void *)时才有效。如果你使用的是64位系统,那么VAL指向4个字节的空间,但你告诉编译器指向8位。如果这个地址位于正确的位置(在你分配的虚拟地址空间的末尾),那么它将会尝试写入void指针的pthread_join中的段错误。

你应该做的是:

void *retval; 
pthread_join(thread, (void **), &retval); 
val = (int)retval; 

从一个指针为int演员将截断任何更显著位。另外,如果它是一个64位的大端系统,你永远不会得到正确的val,因为实际存储数据的4个字节是第二个4字节。

与其他答案相反,通过将整型返回值转换回void *然后返回到所需的整数类型是完全正确的。你只是不想将实际的指针传递给栈中的数据,因为你会调用未定义的行为。在一天结束时,指针只不过是一个无符号整数,其值通常指向内存中的某个位置。