1

我需要将一维数组的前 k 个元素中的每一个移动一个偏移量,其中偏移量是单调递增的,即如果元素 i 的偏移量是 offset1,则元素 i+1 具有偏移量 offset2,它满足:offset2 >= 偏移量1。

我编写了一个在前 k 个元素上执行的内核:

if (thread_id < k) {

  // compute offset

  if (offset) {
    int temp = a[thread_id];

    __synchthreads();

    a[thread_id + offset] = temp;
  }
}

然而,当测试 k = 3 时,偏移量确实是单调增加的,即 0、1、1。元素 0 保持在预期的位置。但是,元素 1 不仅被复制到元素 2(根据元素 1 的偏移量),还被复制到元素 3。

也就是说,似乎只有在线程 1 完成元素 1 到元素 2 的复制之后,线程 2 才读取元素 2 并将其存储到它的 temp 副本中。

我做错了什么以及如何解决?

谢谢!

4

1 回答 1

3

您正在做的事情概括为分散操作:

thread   0  1  2  3  4
in  =  { 1, 4, 3, 2, 5}
idx =  { 1, 2, 3, 4, 0}

out[idx] = in[i]

一般来说,分散不能并行就地完成,因为线程从其他线程写入的位置读取。在我们的示例中,如果线程 2在线程 1 写入其输出位置之后读取其输入位置,则会得到不正确的结果。这是一个竞争条件,需要同步或异地存储。

由于在这种情况下,大型数组的同步是全局同步,CUDA 编程模型不支持,因此您必须使用异地分散。

换句话说,你不能这样做:

temp = in[thread_idx]
global-sync
in[thread_idx + offset] = temp

你必须这样做:

out[i + offset] = in[thread_idx]

Whereout不指向与 . 相同的内存in

于 2013-02-19T10:58:23.073 回答