pthread_cancel之后的分段错误

时间:2018-11-18 04:15:11

标签: c multithreading segmentation-fault pthreads

在我的程序中,我有两个线程,一个线程计算一些递归函数,而另一个线程则显示“进度点”,就像第一个线程进行计算一样。有代码:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#define test_errno(msg) do{if (errno) {perror(msg); exit(EXIT_FAILURE);}} while(0)

void *progressDotsThread(void* _arg){
    for(int i=0;;i++){
    printf(".");
    fflush(stdout);
    sleep(1);
    }
}
void *seriesCalculateThread(void* n){
    int result;

    if((long)n==1) return (void*)(1);
    else if((long)n==2) return (void*)(-5);
    else{
         int nmin1 = (long)seriesCalculateThread( (void*) ( (long)n -1   ));
         int nmin2 = (long)seriesCalculateThread( (void*) ( (long)n -2   ));
         result = nmin1*((long)n)*nmin2;
         return (void*)(result);
    }
}

int main(void) {
    long n=0;
    int result =0;
    pthread_t w1,w2;

    printf("Give n\n");
    scanf ("%d",&n);

    if(n<1){
        printf("Value must be higher than 0");
    }
    else{

        errno= pthread_create(&w2,NULL,seriesCalculateThread,(void *)n);
        test_errno("pthread_create");
        errno= pthread_create(&w1,NULL,progressDotsThread,NULL);
        test_errno("pthread_create");

        if(!pthread_join(w2,(void**)&result)){
            errno = pthread_cancel(w1); //<--- Where segmentation fault happens
            test_errno("pthread_cancel");
        }
        printf("%d\n", result);

    }

    return EXIT_SUCCESS;
}

pthread_create都一个,然后我if(!pthread_join)一个做计算的一个,当计算完成时,我取消了显示点的那个。

if(!pthread_join(w2,(void**)&result)){
                errno = pthread_cancel(w1); //<--- Where segmentation fault happens
                test_errno("pthread_cancel");
            }

我做到了,尽管在调用pthread_cancel(w1)之后出现了分段错误,我也不知道为什么会这样。

我尝试使用gcc -g -Wall -pthread psthreadss.c -lpthread在终端上编译它,但在eclipse中效果不佳。如果可以的话,我会使用Ubuntu 18.04。

1 个答案:

答案 0 :(得分:1)

  

然后我if(!pthread_join)进行计算的那个,当计算结束时,我取消显示点的那个。

您的程序有一个逻辑错误和一个内存损坏错误。

逻辑错误:您假设!pthread_join意味着计算已完成。它不是这个意思。如果您使用不正确的参数(线程ID pthread_join未知,尚未启动或已加入)调用了w2,则仅返回非零状态 。 / p>

您的代码应该看起来像这样:

int rc = pthread_join(w2, ...);
assert(rc == 0);
rc = pthread_cancel(w1);
assert (rc == 0);

出现内存损坏错误:在64位系统(我假设您正在使用)上,sizeof(int) == sizeof(result) == 4,但sizeof(void*) == 8

此代码:

 int result =0;
 ...
    pthread_join(w1, (void**)&result)

接收4字节的地址result,并要求pthread_join在其中存储8字节的值。可以预见的结果是堆栈损坏。

我不知道它是如何触发SIGSEGV的,但是一旦程序中出现未定义的行为,所有的赌注都将消失。

要解决此问题,请将result类型更改为intptr_t。我希望崩溃会在该修复后消失。

您还应该在进行任何更改之前尝试使用Address Sanitizer:gcc -fsanitize=address -g ...。很有可能会告诉您有关堆栈溢出的信息。