Функция, вызываемая pthread_create, прерывается, когда значение присваивается структуре, переданной ей

Я новичок в C. У меня есть небольшая программа, которая предназначена для решения поиска точечного произведения большой 2d матрицы с самим собой, используя pthread. Теперь, когда вызывается функция, назначенная pthread, и происходит доступ к структуре, переданной как переменная, программа прерывается и перестает работать. Я действительно не знаю, что делаю не так. Вот код:

Это основная функция.

int main()
{
    int rc;
    int threadcount = 1;
    char filename[100];

    //patch to enable console printing in eclipse
    setvbuf(stdout, NULL, _IONBF, 0);

    do {
        prompt_for_fileName(filename);

        if (filename[0] == 'Q' || filename[0] == 'q') {
            puts("Program ended");
            return 0;
        }

        //read thread count
        read_threadcount(&threadcount);

        //initialize matrices
        matrix_def matrix = initialize_matrix(filename);

        //get the dimension of sub-matrices
        int dfRow = (int) floor(matrix.NROWS / threadcount);

        pthread_t threads[threadcount];
        pthread_arg pthreadargs[threadcount];
        for (int i = 0; i < threadcount; i++) {
            int startRow = i * dfRow;
            int endRow =
                    ((i + 1) == threadcount) ?
                            matrix.NROWS : (startRow + dfRow) - 1; //we're subtracting one because its zero based.

            //create a structure that we'll passed to the array.
            pthread_arg arg = { matrix.NROWS, matrix.NCOLS, startRow, endRow,
                    0.0, NULL, NULL };
            arg.data = matrix.data;
            arg.result_set = create_result_memory(matrix.NCOLS);

            fprintf(stderr, "before %p\n", arg.result_set);

            //push arg into array.
            pthreadargs[i] = arg;

            rc = pthread_create(&threads[i], NULL, compute_dot_product,
                    (void *) &arg);

            if (rc) {
                printf("ERROR; return code from pthread_create() is %d\n", rc);
                exit(-1);
            }
        }

        /* Last thing that main() should do */
        pthread_exit(NULL);

        puts("Completed processing.");
        double totalTime = 0.0;
        for (int z = 0; z < threadcount; z++) {
            pthread_arg ar = pthreadargs[z];

            printf("Thread %d took %g to process %d rows and %d columns.\n", z,
                    ar.execution_time, ar.endz - ar.start, ar.col);

            totalTime += ar.execution_time;
        }

        printf(
                "It took the total time of %g, to compute the dot product of the matrices.\n",
                totalTime);

        //free memory
        free(matrix.data);
        for (int k = 0; k < threadcount; k++) {
            free(pthreadargs[k].data);
            free(pthreadargs[k].result_set);
        }

    } while (filename[0] != 'Q' || filename[0] != 'q');
}

Это функция, вызываемая pthread

void * compute_dot_product(void * inputArgs) {
    double startTime, endTime;
    pthread_arg * args = inputArgs;

    /*Compute the dimension of the result matrix*/

    int col, row, start, endz;
    col = args->col;
    start = args->start;
    endz = args->endz;
    row = endz - start;

    fprintf(stderr, "after %p\n", args->result_set);

    //create a pointer to the two array
    double **arr1 = args->data;
    double **arr2 = arr1;

    //begin the computation
    int x;
    startTime = seconds();

    //calculate the dot product the two matrices.
    for (x = 0; x < col; x++) {
        double colProduct = 0.0;
        for (int y = start; y < endz; y++) {
            colProduct += arr1[y][x] * arr2[y][x];
        }

        //The code breaks here.
        args->result_set[x] = colProduct;
   }
    endTime = seconds();

    double diff = endTime - startTime;
    args->execution_time = diff;
    return (void *) 4;
}

Это мои определения структуры

typedef struct
{
    int NROWS; /*for m rows*/
    int NCOLS; /*for n columns*/
    double ** data;
} matrix_def;

typedef struct
{
    double execution_time;
    matrix_def matrix;

} compute_result;

typedef struct{
    int row;
    int col;
    int start;
    int endz;
    double execution_time;
    double **data;
    double *result_set;
} pthread_arg;

Распределение памяти по 2D-матрице.

/*dynamically allocate array based on the read size*/
    matrix.data =  (double **) malloc(sizeof(double *) * M);


    if(matrix.data != NULL){
        int x;
        for(x = 0; x < M; x++){
            matrix.data[x] = (double) malloc(sizeof(double) * N);
        }
    }else{
        fprintf(stderr, "Unable to allocate memory\n");
        exit(1);
    }

Функция инициализации матрицы

matrix_def initialize_matrix(char *argv)
{
    int ret_code;
    MM_typecode matcode;
    FILE *f;
    int M, N, nz;
    int i;
    matrix_def matrix;

    if((f = fopen(argv, "r")) == NULL)
    {
        fprintf(stderr, "Reading file: '%s' failed", argv);
        exit(1);
    }

    /*Read matrix banner*/
    if(mm_read_banner(f, &matcode) != 0)
    {
        printf("Could not process Matrix Market banner. \n");
        exit(1);
    }

    /*Check if the current matrix is supported.*/
    if(mm_is_complex(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))
    {
        printf("Sorry, this application does not support ");
        printf("Market Matrix type: [%s]\n", mm_typecode_to_str(matcode));
        exit(1);
    }


    /*find out size of the sparse matrix...*/
    if((ret_code = mm_read_mtx_crd_size(f, &M, &N, &nz)) != 0)
        exit(1);


    /*Assign m, n sizes.*/
    matrix.NROWS = M;
    matrix.NCOLS = N;

    /*dynamically allocate array based on the read size*/
    matrix.data =  (double **) malloc(sizeof(double *) * M);


    if(matrix.data != NULL){
        int x;
        for(x = 0; x < M; x++){
            matrix.data[x] = (double *) malloc(sizeof(double) * N);
        }
    }else{
        fprintf(stderr, "Unable to allocate memory\n");
        exit(1);
    }



    /*Iterate through the created memory location and fill it with zeros*/
    int a, b;
    for(a = 0; a < M; a++){
        for(b = 0; b < N; b++){
            matrix.data[a][b] = 0;
        }
    }

    /*Read the matrix*/
    for(i = 0; i < nz; i++)
    {
        int I = 0, J = 0;
        double val = 0;
        fscanf(f, "%d %d %lg\n", &I, &J, &val);


        //since the matrix market file starts off at
        //1,1 we have to subtract 1 from the index
        //to account for the array which starts off at
        // 0,0
        matrix.data[--I][--J] = val;
    }

    if(f != stdin)
        fclose(f);

    return matrix;
}

Любая помощь будет оценена, так как я не очень уверен с формулой. Спасибо

2 ответа

Решение

arg выходит из области видимости перед выполнением pthread. Измените свой звонок на

 rc = pthread_create(&threads[i], NULL, compute_dot_product, (void *) &pthreadargs[i]);

Вам также понадобится pthread_join перед выходом, на случай, если потоки еще не закончены.

редактировать

1) Замените свой pthread_exit на

int rv;
for (i = 0; i < threadcount; ++i)
    pthread_join(thread[i], &rv);

Обычно вы вызываете pthread_exit внутри потока (например, compute_dot_product) как ненормальный выход. Это возможная причина взлома вашей программы.

2) Когда вы выходите, я не знаю, как вы распределили свою память, но это потенциальная область, где ваш код может быть поврежден. Если вы выделили свою память как

matrix.data = malloc(sizeof(double*) * matrix.NROWS);
matrix.data[0] = malloc(sizeof(double) * matrix.NROWS * matrix.NCOLS);
for (i = 1; i < matrix.NROWS; ++i)
    matrix.data[i] = matrix.data[i - 1] + matrix.NCOLS;

Тогда вы должны освободить как

free(matrix.data[0]);
free(matrix.data);

Если вы выделили каждую строку отдельно, то освободите все строки перед освобождением matrix.data.

3) Так как matrix.data был освобожден, pthreadargs[k].data не должен освобождаться, поскольку он указывает на ту же область памяти, которая уже была освобождена.

arg объект, определенный здесь:

        pthread_arg arg = { matrix.NROWS, matrix.NCOLS, startRow, endRow,
                0.0, NULL, NULL };

выходит из области видимости, пока поток еще работает. Вам нужно как-то предотвратить это, например, выделив его в кучу.

Другие вопросы по тегам