C - разделить дважды, используя pthread причину segfault - PullRequest
0 голосов
/ 04 ноября 2018

Я написал программу для демонстрации этого.

#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);
}

Это приведет к segfault. Но если я заменю double * на int *. Он будет работать без ошибок. Моя среда Ubuntu 18.04 компилируется с использованием gcc. Я не знаю, неверен ли мой код ..

1 Ответ

0 голосов
/ 04 ноября 2018

В вашей программе две добросовестных ошибки. Первое, что я уже рассмотрел в комментариях: объявлена ​​функция 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».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...