如何在 <threads> c++ 中使用和一维数组进行矩阵乘法?

How to do a matrix multiplication using <threads> and a 1-D array in c++?

本文关键字:一维数组 lt threads gt c++      更新时间:2023-10-16

我正在尝试使用线程进行矩阵乘法。但是我没有正确的值。由于矩阵可能很大,因此我使用堆内存。因此,矩阵存储在1-D阵列中。

矩阵始终是一个方形矩阵,因此行的数量和列数等于阵列长度的平方根。如果数组长度为16,则行数为4,列的数量也为4。

我不能使用std::vector,所以这就是为什么使用std::unique_ptr

有4个线程,每个线程都会收到可使用的原始数组的1/4。由于矩阵乘法的性质,这无效,我似乎找不到正确的解决方案。如何将4个线程的任务拆分

auto matrixmultiplication(float* &array1, float* &array2, int arrayLength) {
    unique_ptr<float[]> arrayOut(new float[arrayLength]);
    auto numberOfThreads = 4;
    auto widthMatrix = (int)sqrt(arrayLength);
    auto elementsPerThread = (int)sqrt(arrayLength / numberOfThreads);
    auto mul = [](auto* array1, auto* array2, auto* array3, auto dimension) {
        for (auto x = 0; x < dimension; x++) {
            for (auto y = 0; y < dimension; y++) {
                array3[dimension * x + y] = 0;
                for (auto z = 0; z < dimension; z++) {
                    array3[dimension * x + y] += array1[dimension * x + z] * array2[dimension * z + y];
                }
            }
        }
    };
    vector<thread> threads;
    for (auto i = 0; i < numberOfThreads; i++) {
        threads.push_back(
            thread(
                mul,
                array1 + i * elementsPerThread,
                array2,
                arrayOut.get() + i * elementsPerThread,
                elementsPerThread
            )
        );
    }
    for (auto &thread : threads) {
        thread.join();
    }
    return arrayOut;
};

对于所有线程,我将从第一个矩阵的连续行启动处理,即0th thread将处理0第0行,第1行将处理第1行,等等,等等到第nth线程。

线程处理一行后,必须通过线程数跳到下一行,即,如果我有2个线程,则在0th the -thone Processig第0行之后,它将跳到第二行并进行处理。

让我们在一个工作示例中查看:

#include <iostream>
#include <memory>
#include <vector>
#include <thread>
// multiplies the specified row and column from specified matrices
void multiply(const int* m_1, const int* m_2,
        std::size_t size, std::size_t row, std::size_t col, int* m_res) {
    for(std::size_t i = 0; i < size; ++i)
        m_res[row * size + col] += m_1[row * size + i] * m_2[i * size + col];
}
int main() {
    constexpr int N = 3, THREAD_NUM = 2;
    // matrices to multiply and a matrix for result
    std::unique_ptr<int[]> A(new int[N * N] {
        11, 12, 13, 21, 22, 23, 31, 32, 33
    });
    std::unique_ptr<int[]> B(new int[N * N] {
        1, 0, 0, 0, 1, 0, 0, 0, 1
    });
    std::unique_ptr<int[]> C(new int[N * N] {});
    // create vector for running threads then assign threads to its elements
    std::vector<std::thread> thread_group(THREAD_NUM);
    for(int thread_i = 0; thread_i < THREAD_NUM; ++thread_i)
        thread_group[thread_i] = std::thread([&, thread_i]() {
            // each thread stars from consecutive rows then steps by 
            // the number of threads
            for(int row = thread_i; row < N; row += THREAD_NUM) {
                for(int col = 0; col < N; ++col)
                    multiply(A.get(), B.get(), N, row, col, C.get());
            }
        });
    for(auto& t : thread_group)
        t.join();
    // show the result
    for(int i = 0; i < N; ++i) {
        for(int j = 0; j < N; ++j)
            std::cout << (j ? "t" : "") << C[i * N + j];
        std::cout << std::endl;
    }
}

如果您有两个要乘的矩阵,我们将其称为AB,您只需要将矩阵A行划分为4个零件,然后将零件传递到相应的线程中。当涉及矩阵B时,您需要将对整个矩阵的引用传递给每个线程,因为您需要其所有元素来计算A*B的每一行。这将是线程安全的,因为您将仅从矩阵B读取而不将其读取。