Как передать матрицу в качестве параметра в функции pthread_create ()?

#c #linux #multithreading #operating-system #pthreads

Вопрос:

Я только начал с программирования операционной системы и изучал потоки. Я хочу умножить 2 матрицы и получить их произведение с помощью функций pthread_create(), pthread_join() и pthread_exit (). Однако функция pthread_create() принимает входные данные как void*, в то время как я хочу передать параметр int**.

Я уже пытался:

  1. Передавая m3 [мою результирующую матрицу] в функцию pthread_create (), набрав ее как (void*), а затем набрав ее обратно в (int**) в моей функции threadMultiply, но это не сработало
  2. Ввод m1,m2,m3 в качестве глобальных переменных, но это тоже дало мне ошибки.

Я очень растерян и больше не знаю, как к этому подойти. Любая помощь была бы очень признательна, спасибо

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

int** alloc(int, int);
void display(int**, int, int);
void* threadMultiply(void* para);

int main()
{
    int r1,c1,r2,c2,r3,c3;  // rows and columns of each matrix
    int **m1, **m2, **m3;   // all 3 matrices

    // took inputs for r1,c1,r2,c2
    m1=alloc(r1,c1);
    printf("Enter the %d elements of the first matrixn", r1*c1);
    for(int i=0;i<r1;i  )
        for(int j=0;j<c1;j  )
            scanf("%d", amp;m1[i][j]);
    m2=alloc(r2,c2);
    printf("Enter the %d elements of the second matrixn", r2*c2);
    for(int i=0;i<r2;i  )
        for(int j=0;j<c2;j  )
                scanf("%d", amp;m2[i][j]);
    display(m1, r1, c1);
    display(m2, r2, c2);
        
    if(c1 != r2)
    {
        printf("nMatrices cannot be multiplied, check dimensions");
        return 0;
    }
        
    r3 = r1;
    c3 = c2;
    m3=alloc(r3,c3);
    int MAX_THREADS = r3*c3;
    pthread_t threads[MAX_THREADS];
 
    // Creating threads. 
    for (int i = 0; i < MAX_THREADS; i  ) 
    {
        int *p;
        pthread_create(amp;threads[i], NULL, threadMultiply, (void*)(p));  //variable 'i' is of type int however function takes parameter of type void* so we have to do type-casting
    }
     
    // joining and waiting for all threads to complete
    for (int i = 0; i < MAX_THREADS; i  )
        pthread_join(threads[i], NULL);   
        
        printf("nThe resultant matrix is:");
        display(m3, r3, c3);
        
return 0;
}

int** alloc(int row, int col)
{
    //dynamic memory allocation for first 2 matrices
    int **m=0;
    m=(int**)malloc(row*sizeof(int*));

    for(int i=0;i<row;i  )
    {
        *(m i)=(int*)malloc(col*sizeof(int));
    }
    
return m;
}

void *threadMultiply(void *para)
{
    int i,j,k;
    for(i=0;i<r1;i  )
    {
        for(j=0;j<c2;j  )
        {
            m3[i][j] == 0
                for(k=0;k<c1;k  )                  
                    m3[i][j] =m1[i][k] * m2[k][j];
        }
    }
    printf("thread finished ...");
    pthread_exit(NULL);
}
 

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

Поэтому, прочитав комментарии, я попробовал это еще раз. Код компилируется, но выдает ошибку сегментации и не отображает вторую матрицу

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

typedef struct matrix {  // using struct to reference 2 matrices in the threadMultiply function
    int r1, c1, r2, c2;
    int **m1;
    int **m2;
}mat;

int** alloc(int, int);
void display(int**, int, int);
void accept(int**, int, int);
void* threadMultiply(void* para);

int main()
{
    int r1,c1,r2,c2,r3,c3;  // rows and columns of each matrix
    int **a, **b, **c;  // all 3 matrices
    long int *ret_value;    //using long int, since int cannot be type casted to void
    mat *m;
    printf("Enter the number of rows and columns(m x n) of the first matrixn");
        printf("Rows=");
        scanf("%d", amp;r1);
        printf("Columns=");
        scanf("%d", amp;c1);
        a=alloc(r1,c1);
        printf("Enter the %d elements of the first matrixn", r1*c1);
    accept(a,r1,c1);
        printf("Enter the number of rows and columns(m x n) of the second matrixn");
        printf("Rows=");
        scanf("%d", amp;r2);
        printf("Columns=");
        scanf("%d", amp;c2);
        b=alloc(r2,c2);
        printf("Enter the %d elements of the second matrixn", r2*c2);
    accept(b,r2,c2);
    printf("nThe first matrix is:");
    display(a, r1, c1);
        printf("nThe second matrix is:");
        display(b, r2, c2);
    
        if(c1 != r2)
        {
            printf("nMatrices cannot be multiplied, check dimensions");
            return 0;
        }
        
        r3 = r1;
        c3 = c2;
        c=alloc(r3,c3);
        m->m1 = a;
    m->m2 = b;
    m->r1 = r1;
    m->c1 = c1;
    m->r2 = r2;
    m->c2 = c2;
    
    // Creating one thread for each operation
    int MAX_THREADS = r3*c3;    
    pthread_t threads[MAX_THREADS];
    for (int i = 0; i < MAX_THREADS; i  ) 
    {
        pthread_create(amp;threads[i], NULL, threadMultiply, (void*)(amp;m));  
    }
     
    // joining and waiting for all threads to complete
    for(int i=0;i<MAX_THREADS;i  ) 
    {
        for(int j=0;j<r3;j  ) 
        {
            for(int k=0;k<c3;k  )
            {
                //joining all the threads and retreiving value in ret_value
                if(pthread_join(threads[i],(void **) amp;ret_value) != 0)
                    perror("nThread join failed.n");
                c[j][k]  = (long int)ret_value;   // int doesn't work here for some reason
            }
        }
    }
        
        printf("nThe resultant matrix is:");
        display(c, r3, c3);
        
return 0;
}

int** alloc(int row, int col)
{
    //dynamic memory allocation for first 2 matrices
    int **m=0;
    m=(int**)malloc(row*sizeof(int));

    for(int i=0;i<row;i  )
        *(m i)=(int*)malloc(col*sizeof(int)); //m i so that we can access all the rows by incrementing value of i. (m i) = m[i]
    
return m;
}

void display(int **m, int r, int c)
{
    int i,j;
    for(i=0;i<r;i  )
    {
        printf("n[");
        for(j=0;j<c;j  )
        {
            if(j<c-1)
            {
                printf("%dt", m[i][j]);
            }
            else 
            {
                printf("%d]", m[i][j]);
            }

        }
    }
}

void accept(int **a, int row, int col)
{
    int i, j;
    printf("Enter the elementsn");

    for(i = 0; i < row; i  )
        for(j = 0; j < col; j  )
            scanf("%d", (*(a   i)   j));  //same as a[i][j]
}
void *threadMultiply(void *para)
{
    mat *m = (mat*)para;
    int i = m->r1;
    int j = m->r2;
    int k = m->c2;
    long int return_val = m->m1[i][k] * m->m2[k][j];
    printf("nThread finished ...");
    pthread_exit((void *) return_val);
}
 

Комментарии:

1. Этот код не показывает, что вы пытались передать в виде матрицы, так как вместо этого вы передаете бесполезный указатель p . Вам не нужно бросать на а void * . Вам действительно нужно выполнить приведение para в int ** пределах вашей функции потока.

2. Ваша функция потока ссылается m1 на , m2 , и m3 , но они не определены в этом контексте, поэтому это не должно компилироваться. Вы также не используете параметр функции и не передаете ему ничего значимого. Пожалуйста, покажите одну из ваших фактических попыток с вводом, ожидаемым результатом и фактическим результатом.

3. Вы переходите от pthread_create указателя к указателю на mat . Но в функции потока вы приводите para указатель на mat . Заметили разницу? Примечание: этот комментарий относится к отредактированному коду. Подсказка: Прочитайте и попытайтесь понять рекомендацию, содержащуюся в моем ответе ниже.

4. И вы объявляете mat *m (указатель на mat), но никогда не назначаете для него хранилище. Но некоторые строки ниже вас разыменовывают m .

Ответ №1:

Рекомендация: Объявление указателя (cppreference.com)

Там, в разделах,

Объяснение

Указатели используются для косвенного использования, что является повсеместным методом программирования; их можно использовать для реализации семантики ссылок на переход, для доступа к объектам с динамической длительностью хранения, для реализации «необязательных» типов (с использованием значения нулевого указателя), связи агрегирования между структурами, обратных вызовов (с использованием указателей на функции), универсальных интерфейсов (с использованием указателей на пустоту) и многого другого.

Указатели на пустоту

Указатель на объект любого типа может быть неявно преобразован в указатель на пустоту (необязательно const или с изменчивой квалификацией), и наоборот:

Указатели на void используются для передачи объектов неизвестного типа, что часто встречается в универсальных интерфейсах: malloc возвращает void*, qsort ожидает предоставленный пользователем обратный вызов, который принимает два аргумента const void*. pthread_create ожидает предоставленный пользователем обратный вызов, который принимает и возвращает значение void*. Во всех случаях ответственность за преобразование указателя в правильный тип перед использованием лежит на вызывающем абоненте.


Как это относится к вашему коду

В вашей основной функции:

 // Creating threads. 
for (int i = 0; i < MAX_THREADS; i  ) {
    int *p; // <- WARNING: pointer to int is uninitialized
    pthread_create(
        amp;threads[i], 
        NULL, 
        threadMultiply, 
        (void*)(p) // <- here you don't have to cast to void*
    );
}
 

Указатель p неинициализирован. Назначьте p адрес любому объекту, который вы хотите передать в качестве аргумента (параметра) функции запуска потока.

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

Пример:

 //global
struct arg {
    int r1, c1, r2, c2, r3, c3;
    int **m1;
    int **m2;
    int **m3;
};

int main()
{
    //...

    struct arg p = {
        r1, c1, 
        r2, c2, 
        r3, c3, 
        m1, m2, m3
    }; //for demonstration purposes only, 
       //normally you would have to allocate a struct for each thread

    pthread_create(amp;threads[i], NULL, threadMultiply, amp;p); //need address of operator

    //...

}
 

Чтобы избежать введения новой структуры, вы, конечно, можете объявить все переменные глобальными, но с помощью структуры вы можете передавать разные параметры разным потокам (одновременно).

Затем функция умножения:

 void *threadMultiply(void *para)
{
    struct arg *p = para; //implicit cast
    int r1 = p->r1;
    int c1 = p->c1;
    //...
    int **m1 = p->m1;
    //...
    //do your multiplication
}
 

Комментарии:

1. Большое спасибо! Я попробую это сделать и дам вам знать

2. Я отредактировал код. Теперь у меня ошибка сегментации