C-使用pthread导致段segfault共享两次

时间:2018-11-04 18:58:19

标签: c pthreads

我编写了一个程序来演示这一点。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>

#include <time.h>       /* clock_t, clock, CLOCKS_PER_SEC */
#include <math.h>       /* sqrt */
struct thread_args
{

    double* producer_clock;
    double* producer_time;
    double* consumer_time;
    double* consumer_clock;



};
void *producer(void* thread_args){
  struct thread_args* thread_arg=(struct thread_args*)thread_args;
    double* producer_time=(double*)(thread_arg->producer_time);
    double* producer_clock=(double*)(thread_arg->producer_clock);
    double* consumer_time=(double*)(thread_arg->consumer_time);
    double* consumer_clock=(double*)(thread_arg->consumer_clock);
    *producer_time=0;
    *producer_clock=0;
    *consumer_time=0;
    *consumer_clock=0;
}
int main(){
  pthread_t tid1;
  double* producer_time=(double*)malloc(sizeof(double));
       double* producer_clock=(double*)malloc(sizeof(double));
       double* consumer_time=(double*)malloc(sizeof(double));
    double* consumer_clock=(double*)malloc(sizeof(double));
    struct thread_args* thread_arg;
    thread_arg=(struct thread_args*)malloc(sizeof(struct thread_args*));
    thread_arg->producer_time=producer_time;
    thread_arg->producer_clock=producer_clock;
    thread_arg->consumer_time=consumer_time;
    thread_arg->consumer_clock=consumer_clock;
    pthread_create(&tid1,NULL,producer,(void*)thread_arg);
    pthread_join(tid1,NULL);
}

这将导致段错误。但是,如果我将double *替换为int *。它将运行而不会出现错误。我的环境是使用gcc编译的Ubuntu 18.04。我不知道我的代码是否错误..

1 个答案:

答案 0 :(得分:0)

您的程序中有两个善意错误。首先,我已经在注释中谈到过:您的producer()函数被声明为返回值,但实际上并没有这样做。结果,调用此函数将产生未定义的行为。由于您实际上并没有使用返回值,因此可以简单地通过使函数返回NULL来解决此问题。

但是,您的main()函数为thread_arg分配的空间太小可能更具影响力:

    thread_arg=(struct thread_args*)malloc(sizeof(struct thread_args*));

您正在分配一个指针大小的空间,但是您需要一个struct thread_args足够的空间,该空间肯定更大(在Ubuntu上),因为它包含四个指针。 C不需要指向不同对象类型的指针具有相同的大小,但是在Linux上,它们是相同的。因此,正确的分配应该是

    thread_arg = (struct thread_args*) malloc(sizeof(struct thread_args));

但是,在C语言中,强制转换malloc()的结果的格式很差,该语言不需要它,这样做会掩盖编译器将报告给您的错误。 (这在C ++中是不同的。)因此,这将是更好的形式:

    thread_arg = malloc(sizeof(struct thread_args));

这同样适用于所有赋值,其中一侧是指向void的指针,另一侧是指向任何对象类型的指针,也适用于将参数传递给非varargs函数。

但是我们可以做得更好。请注意,从该语句本身并不能立即得知thread_arg的类型是什么,以便验证是否分配了正确的字节数。还考虑一下如果后来将thread_arg更改为其他类型,而忽略了将该分配固定为对应类型的情况,会发生什么情况。这些问题可以通过使用所需类型的表达式而不是通过该类型的名称来设置大小来解决:

    thread_arg = malloc(sizeof(*thread_arg));

请注意,sizeof()的参数不会被求值(除非它的类型是可变长度的,在这里不是这种情况),因此在使用表达式*thread_arg之前没有问题将一个值分配给thread_arg。由此得出的陈述显然是明确正确的。用英语说:“分配thread_arg指向的对象的大小的空间,并将指向该空间的指针分配给thread_arg”。