被问到c ++ 11中的多线程矩阵乘法

时间:2014-02-11 21:26:38

标签: c++ multithreading c++11 matrix

截至目前,我的每个功能都有两个线程。 Ax和Sword是Matrix对象。

thread thrd1(Add, std::ref(Axe), std::ref(Sword), std::ref(Axe));
thread thrd2(Multiply, std::ref(Axe), std::ref(Sword), std::ref(Axe));

我是线程新手,并不太了解它。我是否必须在我的乘法函数中添加线程?现在它只是

//Multiply the matrices
void Multiply(Matrix &a, Matrix &b, Matrix &c){
    for (auto i=0; i<c.dx; ++i) {
        for (auto j=0; j<c.dy; ++j) {
            for (auto k=0; k<a.dy; ++k) {
                c.p[i][j] += a.p[i][k] * b.p[k][j];
            }
        }
    }
}

但我感觉好像我需要添加其他东西,因为它们在通过openMP设置线程数时没有减少时间。任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:1)

你所要做的就是这个

void Multiply(Matrix &a, Matrix &b, Matrix &c) {
    #pragma omp parallel for
    for (int i=0; i<c.dx; ++i) {
        for (int j=0; j<c.dy; ++j) {
            for (int k=0; k<a.dy; ++k) {
                c.p[i][j] += a.p[i][k] * b.p[k][j];
            }
        }
    }
}

您可能不想担心线程数量。让OpenMP选择默认值。这将被设置为逻辑核心的数量。但是,如果您有超线程,则可能有助于将线程数设置为物理核心数而不是逻辑核心数。

您也可能想尝试融合循环。喜欢这个

#pragma omp parallel for
for(int n=0; n<c.dx*c.dy; n++) {
    int i=n/c.dy;
    int j=n%c.dy;

但是,当您阅读b.p[k][j]时,它可能会有很多缓存未命中。一个更好的解决方案是采用b的转置并以b.p [j] [k]的形式访问转置。

更好的解决方案是使用平铺/块矩阵乘法。请参阅以下链接,了解如何执行此操作reading/writing a matrix with a stride much larger than its width causes a big loss in performance

答案 1 :(得分:0)

首先:OpenMP和std :: thread / future / etc。是不同的事情。如果你想使用OpenMP,那里有一些非常好的教程可供查找,但它可以归结为你的第一个循环前面的一个预处理器命令。

现在转到c ++ 11部分:我想你的问题(在这方面还不太清楚),你传递的函数是在一个线程中运行的。这不会减少任何计算时间,因为您的代码仍在一个线程中运行。现在猜猜“多线程”中的“多”是什么意思......

每次编写多线程代码时,您想要做的是

  1. 考虑如何将您的工作分成(理想情况下大小相同)不相交问题。这里不相交意味着无论你在计算什么,都不依赖于其他计算的结果。在您的情况下,请注意矩阵或列/行的单个结果元素的计算可以独立于其他元素计算。

  2. 无论这样的“子计算”写入必须写入其他线程不同时写入的位置。如果这是必要的,有办法解决这个问题(例如互斥),但通常可以将问题定义为在内存中本身独立(例如,在每种情况下,每个工作线程只能在一列中写入)。

  3. 编写一个执行此类子任务的函数(例如,将您的函数限制为仅计算作为参数传递的一个列),并为所有子任务创建std :: thread或std :: future对象(后者)使用std :: async),将它们的子任务函数与它们相应的参数传递给它们并等待它们完成(使用thread :: join)。

  4. 请注意,在任何非纯函数语言中编写多线程代码来解决那些不太重要的问题很快就会变得非常复杂。您可能需要一些时间阅读一些教程或书籍。首先,请查看此YouTube列表:https://www.youtube.com/playlist?list=PL5jc9xFGsL8E12so1wlMS0r0hTQoJL74M

    哦,在我忘记它之前: 在您的函数中,您不需要写入ab,因此应该通过const引用传递它们。在线程构建站点上,您必须使用std::cref。编写多线程代码时,Const正确性非常重要。