#c #linux #multithreading #operating-system #pthreads
Вопрос:
Я только начал с программирования операционной системы и изучал потоки. Я хочу умножить 2 матрицы и получить их произведение с помощью функций pthread_create(), pthread_join() и pthread_exit (). Однако функция pthread_create() принимает входные данные как void*, в то время как я хочу передать параметр int**.
Я уже пытался:
- Передавая m3 [мою результирующую матрицу] в функцию pthread_create (), набрав ее как (void*), а затем набрав ее обратно в (int**) в моей функции threadMultiply, но это не сработало
- Ввод 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. Я отредактировал код. Теперь у меня ошибка сегментации