我正在尝试在cuda中进行矩阵乘法。我的实现与cuda示例不同。
cuda示例(来自cuda样本)通过将第一个矩阵的行中的每个值乘以第二个矩阵的列中的每个值来执行矩阵乘法,然后对乘积求和并将其存储在输出向量中。来自第一个矩阵的行的索引。
我的实现将第一个矩阵的列中的每个值乘以第二个矩阵的行的单个值,其中行索引=列索引。然后它在全局内存中有一个输出向量,它的每个索引都已更新。
cuda示例实现可以让单个线程更新输出向量中的每个索引,而我的实现可以有多个线程更新每个索引。
我得到的结果只显示了一些值。例如,如果我有4次迭代更新,它只会做2或1.
我认为线程可能互相干扰,因为它们都试图写入全局内存中向量的相同索引。那么也许,当一个线程写入索引时,另一个线程可能无法插入其值并更新索引?
只是想知道这种评估是否有意义。
例如。要乘以以下两个矩阵:
[3 0 0 2 [1 [a
3 0 0 2 x 2 = b
3 0 0 0 3 c
0 1 1 0] 4] d]
Cuda样本使用4个线程以下列方式进行矩阵乘法,其中a,b,c,d存储在全局存储器中:
Thread 0: 3*1 + 0*2 + 0*3 + 2*4 = a
Thread 1: 3*1 + 0*2 + 0*3 + 2*4 = b
Thread 2: 3*1 + 0*2 + 0*3 + 0*4 = c
Thread 3: 0*1 + 1*2 + 1*3 + 0*4 = d
我的实现如下:
a = b = c = d = 0
Thread 0:
3*1 += a
3*1 += b
3*1 += c
0*1 += d
Thread 1:
0*2 += a
0*2 += b
0*2 += c
1*2 += d
Thread 2:
0*3 += a
0*3 += b
0*3 += c
1*3 += d
Thread 3:
2*4 += a
2*4 += b
0*4 += c
0*4 += d
所以有一次所有四个线程都试图更新其中一个索引。
答案 0 :(得分:1)
为了解决此问题,我使用 atomicAdd 执行 + = 操作。当一个线程执行操作 3 * 1 + = a (例如)时,它会做三件事。
- 它获得 a
的先前值- 通过 3 * 1 + 之前的 a
值更新值- 然后将新值存储到 a
中 醇>
通过使用atomicAdd,它保证线程可以在不中断其他线程的情况下发生这些操作。如果未使用 atomicAdd ,则thread0可以获得 a 的先前值,而当thread0正在更新该值时,thread1可以获得 a 并执行自己的更新。这样就不会发生 + = 操作,因为线程无法完成操作。
如果使用 a + = 3 * 1 而不是 atomicAdd(& a,3 * 1),则thread1可能会干扰并更改thread0完成它正在做的事之前thread0的值。它创造了竞争条件。
atomicAdd 是 + = 操作。您将使用以下代码执行操作:
__global__ void kernel(){
int a = 0;
atomicAdd(&a, 3*1); //is the same as a += 3*1
}