要求在c++11中实现多线程矩阵乘法

Asked to multithread matrix multiplication in c++11

本文关键字:多线程 实现 c++11      更新时间:2023-10-16

到目前为止,我的每个函数都有两个线程。斧头和剑是矩阵的对象。

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设置线程数量时,它们不会减少时间。有人能帮我吗?

你所要做的就是这个

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]。

一个更好的解决方案是使用瓦片/块矩阵乘法。请参阅以下链接,了解如何读取/写入跨步远大于其宽度的矩阵会导致性能的巨大损失

首先:OpenMP和std::thread/forent/等。是不同的东西。如果你想使用OpenMP,有一些非常好的教程可以寻找,但我想它可以归结为第一个循环前的一个预处理器命令。

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

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

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

  2. 无论这种"子计算"写入的内容是什么,都必须写入其他线程不同时写入的位置。如果有必要,有一些方法可以解决这个问题(例如互斥),但通常情况下,问题可以被定义为在内存中固有的独立性(例如,在您的情况下,每个工作线程只能写入一列)。

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

请注意,用任何非纯函数语言为不那么琐碎的问题编写多线程代码都可能很快变得相当复杂。你可能应该花点时间读一些教程或书籍。作为一个开始,也许可以看看这个youtube列表:https://www.youtube.com/playlist?list=PL5jc9xFGsL8E12so1wlMS0r0hTQoJL74M

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