Матричное умножение с потоками C - PullRequest
0 голосов
/ 12 марта 2019

Я пытаюсь умножить данные матрицы и сохранить результат в глобальной матрице, используя многопоточность. Вот код:

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

struct mat_size {
    int row;
    int column;
};
struct mat_values {
    int * m_1;
    int * m_2;
    int i;
    int j;
};
int * result_matrix;
struct mat_size * result_size;
void * matrix_row_result(void * input) {
    struct mat_values *indicators = (struct mat_values *)input;
    int i = indicators->i;
    int j = indicators->j;
    int *m_1 = indicators->m_1;
    int *m_2 = indicators->m_2;

    int result = 0;
    int it = i;

    for(; it < result_size->column; it++)
    {
        printf("%d += %d * %d, ", result, *(m_1 + i * result_size->column + it), *(m_2 + it * result_size->column + j));
        result += *(m_1 + i*result_size->column + it) * *(m_2 + it*result_size->column + j);
    }
    putchar('\n');
    *(result_matrix + i * result_size->column + j) = result;
    // printf("%d ", *(result_matrix + i * result_size->column + j));
    pthread_exit(0);
}

void parallel_matrix_mult(int * m_1, int * m_2, int m, int n) {
    pthread_t * threads;

    result_size = (struct mat_size *)malloc(sizeof(struct mat_size));

    result_size->row = m;
    result_size->column = n;

    int number_threads = (result_size->row) * (result_size->column);
    printf("Creating %d threads and allocating %d size for final matrix\n", number_threads, number_threads * sizeof(int));
    result_matrix = calloc(m * n, sizeof(int));

    threads = (pthread_t *)calloc(number_threads, sizeof(pthread_t));
    int curr_thread = 0;
    for(size_t i = 0; i < result_size->row; i++) {
        for(size_t j = 0; j < result_size->column; j++) {
            printf("Allocating %d, %d to thread %d\n", i, j, curr_thread);
            struct mat_values *m_values = (struct mat_values *)malloc(sizeof(struct mat_values));
            m_values->m_1 = m_1;
            m_values->m_2 = m_2;
            m_values->i = i;
            m_values->j = j;
            int status = pthread_create((threads + curr_thread), NULL, matrix_row_result, m_values);
            printf("%d Status for thread %d\n", status, curr_thread);
            pthread_join(*(threads + curr_thread), 0);
            free(m_values);
            ++curr_thread;
        }
    }

    for(size_t i = 0; i < result_size->row; i++)
    {
        putchar('\n');
        for(size_t j = 0; j < result_size->column; j++)
        {
            printf("%d ", *(result_matrix + i * result_size->column + j));
        }

    }
    putchar('\n');
    free(result_size);
    free(result_matrix);
    free(threads);
}

int main() {
    int matrix_1[4][2] = {
        {1, 2},
        {3, 4},
        {5, 6},
        {7, 8}};
    int matrix_2[2][2] = {
        {1, 1},
        {1, 1}};
    int m = sizeof(matrix_1) / sizeof(matrix_1[0]);
    int n = sizeof(matrix_2[0]) / sizeof(int);
    printf("Rows: %d and Columns: %d\n", m, n);
    parallel_matrix_mult((int *)matrix_1, (int *)matrix_2, m,  n);
    return 0;
}

Кажется, проблема в том, что я не понимаю многопоточность. Я хочу, чтобы каждый поток выполнял операцию между i-й строкой матрицы 1 и j-м столбцом матрицы 2. Пример кода без многопоточности выглядит следующим образом:

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

int main() {
    int matrix_1[4][2] = {
        {1, 2},
        {3, 4},
        {5, 6},
        {7, 8}
    };
    int matrix_2[2][2] = {
        {1, 1},
        {1, 1}
    };
    int * result_matrix;
    int * m = (int *) matrix_1;
    int * m2 = (int * ) matrix_2;

    result_matrix = (int * ) calloc(4 * 2, sizeof(int));
    for(size_t i = 0; i < 4; i++)
    {   
        putchar('\n');
        for(size_t j = 0; j < 2; j++)
        {
            for(size_t x = 0; x < 2; x++)
            {
                *(result_matrix + i * 2 + j) += *(m + i * 2 + x) * *(m2 + x * 2 + j);
            }
            printf("%d ", *(result_matrix + i * 2 + j));
        }
    }
    free(result_matrix);
}

Теперь проблема в том, что когда я запускаю последовательный код, он выводит:

3 3 
7 7 
11 11 
15 15

как и ожидалось; с другой стороны, в параллельной программе это результат

3 3 
4 4 
0 0 
0 0

Вот некоторые отладочные сообщения, которые я использовал:

Rows: 4 and Columns: 2
Creating 8 threads and allocating 32 size for final matrix
Allocating 0, 0 to thread 0
0 Status for thread 0
0 += 1 * 1, 1 += 2 * 1, 
Allocating 0, 1 to thread 1
0 Status for thread 1
0 += 1 * 1, 1 += 2 * 1, 
Allocating 1, 0 to thread 2
0 Status for thread 2
0 += 4 * 1, 
Allocating 1, 1 to thread 3
0 Status for thread 3
0 += 4 * 1, 
Allocating 2, 0 to thread 4
0 Status for thread 4

Allocating 2, 1 to thread 5
0 Status for thread 5

Allocating 3, 0 to thread 6
0 Status for thread 6

Allocating 3, 1 to thread 7
0 Status for thread 7

1 Ответ

0 голосов
/ 12 марта 2019

Для каждого результата, который вы хотите сгенерировать, вам нужно 2 умножения и одно сложение.Как и

result = matrix_1[3][0] * matrix_2[0][0] + matrix_1[3][1] * matrix_2[0][1];

, но это не то, что делает ваш код.

Посмотрите на это:

int it = i;

for(; it < result_size->column; it++)
{
    printf("%d += %d * %d, ", result, *(m_1 + i * result_size->column + it), *(m_2 + it * result_size->column + j));
    result += *(m_1 + i*result_size->column + it) * *(m_2 + it*result_size->column + j);
}

Значение result_size->column всегда равно 2Однако значение i и, следовательно, значение it следует за номером строки (то есть 0, 1, 2, 3).

Таким образом, только первые два потока выполняют цикл дважды.Другие потоки - нет, и, следовательно, результат неправильный.

Это также видно из печати отладки:

0 Status for thread 0
0 += 1 * 1, 1 += 2 * 1,          // Two loops
Allocating 0, 1 to thread 1
0 Status for thread 1
0 += 1 * 1, 1 += 2 * 1,          // Two loops 
Allocating 1, 0 to thread 2
0 Status for thread 2
0 += 4 * 1,                      // One loops
Allocating 1, 1 to thread 3
0 Status for thread 3
0 += 4 * 1,                      // One loops 
Allocating 2, 0 to thread 4
0 Status for thread 4
                                 // No loops
Allocating 2, 1 to thread 5
0 Status for thread 5
                                 // No loops

Так что вам нужно пересмотреть свой алгоритм.

Кстати: совет ... начните с того, что функция matrix_row_result будет работать без использования потоков.Затем, когда работает в последовательном режиме, вы можете добавить потоковую часть.Другими словами, выполнение «создать» с последующим «объединением»:

        int status = pthread_create((threads + curr_thread), NULL, matrix_row_result, m_values);
        pthread_join(*(threads + curr_thread), 0);

- это нормально при отладке функции. Когда она работает, вы выводите объединение из цикла.

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