Тренируюсь с pthreads, но у меня в коде неожиданное поведение - PullRequest
0 голосов
/ 18 мая 2019

Я хочу создать программу на языке c, которая будет суммировать квадратные числа массива с использованием pthreads для достижения параллельного выполнения кода, но при выполнении кода в среде linux я получаю ошибка сегментации (бездействие ядра) сообщение.

Странная вещь в том, что когда я запускаю один и тот же точный код в среде Windows через DevC ++, код выполняется без проблем.

Кроме этого, похоже, что только 1 поток выполняет работу, выполненную в результате последовательного выполнения.

Я не знаю, ошибаюсь ли я, но pthread_self() возвращает тот же идентификатор.Я все еще новичок в pthreads и программировании в целом, и я не могу найти проблему, поэтому мне нужна ваша помощь.

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
#include <math.h>

void *calculation(int table[], int k);


pthread_mutex_t sum_mutex = PTHREAD_MUTEX_INITIALIZER;
int  n, p, sum = 0;

int main()
{
    int i, k=0, check, *table;

    printf("Give the number of threads:\n");
    scanf("%d",&p);
    pthread_t threads[p];

    printf("Give the number of elements of the table:");
    do{
    printf("The number of elements must be an integral multiple of the number of threads\n");
    scanf("%d",&n);
    check=n%p;
    if(check!=0){
    printf("Jesus how hard is it?\n");
    printf("Try one more time\n");
    printf("Give the number of elements of the table:\n");
    }
    }while(check!=0);

    table = (int*) malloc(n * sizeof(int));
    if(table == NULL){          
        printf("Error! Memory not allocated.\n");
        exit(0);
    }

    printf("Give the elements of the table:\n");
    for(i=0;i<n;i++){
        scanf("%d",&table[i]);
    }

    for(i=0;i<p;i++){                                                       //thread creation
        pthread_create(&threads[i], NULL, calculation(table, k), NULL);
        k++;                                                                //k is a variable used to seperate table, explained later
    }
    for(i=0;i<p;i++){
        pthread_join(threads[i],NULL);
    }

    printf("Sum of vector= %d\n",sum);

    free(table);
    exit(0);
    return 0;
}

void *calculation(int table[], int k){
    int i;
    int local_sum=0;
    for(i=(n/p)*k;i<(n/p)*(k+1);i++)                                        //this algorithm seperates the table into equivelant pieces and
    {                                                                       //every pthread is calculating its given piece then stores that value in its local variable sum
        if((n/p)>n){                                                        //then it is updating the global variable
            pthread_exit(NULL);
        }
        local_sum+=pow(table[i], 2);
        printf("Thread's %lu calculation is %d\n", pthread_self(), local_sum);
    }

    pthread_mutex_lock(&sum_mutex);                                         //mutex used here to protect the critical code
    sum += local_sum;
    pthread_mutex_unlock(&sum_mutex);
}

Если я не ошибаюсь, поток запускает другую «копию»код, таким образом, локальная переменная отличается для каждого потока.После вычисления local_sum он обновляет глобальную сумму, которая защищена по очевидным причинам.

Как я уже говорил, в среде Windows этот код работает без сбоев, но кажется, что тот же pthread выполняет всю работу.Вместо этого работа должна быть разделена на столько частей, сколько существует потоков.

Не забывайте тот факт, что в среде linux ядро ​​вообще не работает, что приводит к ошибке: ошибка сегментации (ядро не работает).

1 Ответ

2 голосов
/ 18 мая 2019

Со страницы руководства объявление pthread_create

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                     void *(*start_routine) (void *), void *arg);

3-й аргумент pthread_create - это указатель на функцию, который принимает void* в качестве аргумента. В вашем случае у вас есть два аргумента void *calculation(int table[], int k);

Также неправильный способ передачи аргумента в pthread_create, это должно быть только имя функции, а не ее параметр (подробнее о функциях обратного вызова). Последние NULL должны быть параметрами. В вашем случае вы хотите передать table и k, но это должен быть один указатель.

pthread_create(&threads[i], NULL, calculation(table, k), NULL);

Ниже я изменил код и представил новый struct thread_arg, который содержит table и k, этот struct будет передан вашему calculation, который затем развернет его и будет использовать в обычном режиме.

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
#include <math.h>

struct thread_arg {
        int *table;
        int k;
};

void *calculation(void *);

pthread_mutex_t sum_mutex = PTHREAD_MUTEX_INITIALIZER;
int  n, p, sum = 0;

int main()
{
        int i, k=0, check, *table;

        printf("Give the number of threads:\n");
        scanf("%d",&p);
        pthread_t threads[p];

        printf("Give the number of elements of the table:");
        do{
                printf("The number of elements must be an integral multiple of the number of threads\n");
                scanf("%d",&n);
                check=n%p;
                if(check!=0){
                        printf("Jesus how hard is it?\n");
                        printf("Try one more time\n");
                        printf("Give the number of elements of the table:\n");
                }
        }while(check!=0);

        table = (int*) malloc(n * sizeof(int));
        if(table == NULL){
                printf("Error! Memory not allocated.\n");
                exit(0);
        }

        printf("Give the elements of the table:\n");
        for(i=0;i<n;i++){
                scanf("%d",&table[i]);
        }

        // edit: since I know the size allocated memory for th_args;
        struct thread_arg th_args[p];

        for(i=0;i<p;i++){                                                       //thread creation
                th_args[i].table = table;
                th_args[i].k = k;
                pthread_create(&threads[i], NULL, calculation, &th_args[i]);
                k++;                                                                //k is a variable used to seperate table, explained later
        }
        for(i=0;i<p;i++){
                pthread_join(threads[i],NULL);
        }

        printf("Sum of vector= %d\n",sum);

        free(table);
        exit(0);
        return 0;
}

void *calculation(void *data){
        int i;
        int local_sum=0;
        int *table;
        int k;

        struct thread_arg *th_args = data;
        k = th_args->k;
        table = th_args->table;

        printf("shubham: thread_spawned\n");
        for(i=(n/p)*k;i<(n/p)*(k+1);i++)                                        //this algorithm seperates the table into equivelant pieces and
        {                                                                       //every pthread is calculating its given piece then stores that value in its local variable sum
                if((n/p)>n){                                                        //then it is updating the global variable
                        pthread_exit(NULL);
                }
                local_sum+=pow(table[i], 2);
                printf("Thread's %lu calculation is %d\n", pthread_self(), local_sum);
        }

        pthread_mutex_lock(&sum_mutex);                                         //mutex used here to protect the critical code
        sum += local_sum;
        pthread_mutex_unlock(&sum_mutex);

        // edit: function returs NULL;
        return NULL;
}

Edit1: теперь calculation возвращает NULL, обработал случай k++, создав p th_args

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