0

我正在尝试将一些任务“映射”到 CUDA GPU。有 n 个任务要处理。(见伪代码)

malloc an boolean array flag[n] and initialize it as false.
for each work-group in parallel do
    while there are still unfinished tasks do
        Do something;
        for a few j_1, j_2, .. j_m (j_i<k) do
            Wait until task j_i is finished; [ while(flag[j_i]) ;  ]
            Do Something;
        end for
        Do something;
        Mark task k finished;  [  flag[k] = true;  ]
    end while
end for

出于某种原因,我将不得不在不同的线程块中使用线程。

问题是如何实现等待任务 j_i 完成;标记任务 k 完成;在 CUDA 中。我的实现是使用布尔数组作为标志。然后在任务完成后设置标志,并读取标志以检查任务是否完成。

但它只适用于小案例,一个大案例,GPU 因未知原因而崩溃。有没有更好的方法来实现 CUDA 中的等待标记

这基本上是CUDA上的线程间通信问题。

4

4 回答 4

2

在线程块中同步很简单,使用__syncthreads(). 然而线程块之间的同步更加棘手 - 编程模型方法是分成两个内核。

如果你仔细想想,这是有道理的。执行模型(对于 CUDA 和 OpenCL)适用于在处理单元上执行的一大堆块,但没有说明何时执行。这意味着一些块将被执行,但其他块不会(它们将等待)。因此,如果您有一个__syncblocks()then 您将面临死锁的风险,因为那些已经执行的将停止,但那些未执行的将永远不会到达障碍。

您可以在块之间共享信息(例如,使用全局内存和原子),但不能共享全局同步。

根据您尝试做的事情,通常有另一种解决或分解问题的方法。

于 2012-09-12T20:54:07.647 回答
1

您所要求的并不容易完成,因为线程块可以按任何顺序安排,并且没有简单的方法可以在它们之间进行同步或通信。从 CUDA 编程指南:

对于并行工作负载,在算法中由于某些线程需要同步以相互共享数据而破坏并行性的点,有两种情况: 这些线程属于同一个块,在这种情况下,它们应该使用 __syncthreads () 并在同一个内核调用中通过共享内存共享数据,或者它们属于不同的块,在这种情况下,它们必须使用两个单独的内核调用通过全局内存共享数据,一个用于写入,一个用于从全局内存中读取。第二种情况不太理想,因为它增加了额外内核调用和全局内存流量的开销。

因此,如果您不能在一个线程块中满足您需要的所有通信,则需要进行多个内核调用才能完成您想要的。

我不相信 OpenCL 有什么不同,但我也不在 OpenCL 中工作。

于 2012-09-12T20:58:10.827 回答
1

这种问题最好通过稍微不同的方法来解决:

不要将固定任务分配给您的线程,迫使您的线程等待它们的任务可用(这在 CUDA 中是不可能的,因为线程不能阻塞)。

相反,保留一个可用任务列表(使用原子操作)并让每个线程从该列表中获取一个任务。

这仍然很难实现并正确处理极端情况,但至少这是可能的。

于 2012-09-12T22:59:25.590 回答
0

我认为你不需要在 CUDA 中实现。每件事都可以在 CPU 上实现。您正在等待一项任务完成,然后随机执行另一项任务。如果你想在 CUDA 中实现,你不需要等待所有的标志都为真。您最初知道所有标志都是错误的。因此,只需Do something为所有线程并行实现并将标志更改为 true。

如果你想在CUDA中实现,int flag在完成之后继续加1,Do something这样你就可以知道在做之前和之后flag的变化Do something

如果我的问题错了,请发表评论。我会努力改进答案。

于 2012-09-14T18:43:50.083 回答