我正在尝试将一些任务“映射”到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
出于某种原因,我将不得不在不同的线程块中使用线程。
问题是如何在CUDA中实现等到任务j_i完成; 和标记任务k完成; 。我的实现是使用布尔数组作为标志。然后在任务完成后设置标志,并读取标志以检查任务是否完成。
但它只适用于小案例,一个大案例,GPU因未知原因而崩溃。有没有更好的方法在CUDA中实施等待和标记。
这基本上是CUDA上线程间通信的问题。
答案 0 :(得分:2)
使用__syncthreads()
在线程块内进行同步非常简单。然而,线程块之间的同步更棘手 - 编程模型方法是分成两个内核。
如果你考虑一下,这是有道理的。执行模型(对于CUDA和OpenCL)是针对在处理单元上执行的一大堆块,但没有说明何时。这意味着一些块将被执行但其他块将不会(它们将等待)。所以,如果你有一个__syncblocks()
那么你就会冒死锁,因为那些已经执行的会停止,但那些没有执行的人永远不会到达障碍。
您可以在块之间共享信息(例如,使用全局内存和原子),但不能在全局同步之间共享信息。
根据您尝试做的事情,经常有另一种解决或解决问题的方法。
答案 1 :(得分:1)
您要求的内容并不容易,因为线程块可以按任何顺序进行调度,并且没有简单的方法可以在它们之间进行同步或通信。来自CUDA编程指南:
对于并行工作负载,在算法中由于某些线程需要同步以便彼此共享数据而导致并行性被破坏的点,有两种情况:这些线程属于同一个块,在这种情况下它们是应该使用__syncthreads()并在同一内核调用中通过共享内存共享数据,或者它们属于不同的块,在这种情况下,它们必须使用两个单独的内核调用通过全局内存共享数据,一个用于写入,一个用于从全局读取记忆。第二种情况不太理想,因为它增加了额外内核调用和全局内存流量的开销。因此,应该通过将算法映射到CUDA编程模型来最小化它的出现,使得需要线程间通信的计算尽可能在单个线程块内执行。
因此,如果您无法在线程块中满足所需的所有通信,则需要进行多次内核调用才能完成所需的操作。
我不认为与OpenCL有任何区别,但我也不在OpenCL中工作。
答案 2 :(得分:1)
这种问题最好用稍微不同的方法解决:
不要将固定任务分配给线程,强制线程等到它们的任务可用(这在CUDA中是不可能的,因为线程无法阻塞)。
相反,保留可用任务列表(使用原子操作)并让每个线程从该列表中获取任务。
这仍然很难实现并使角落案件正确,但至少它是可能的。
答案 3 :(得分:0)
我认为你不需要在CUDA中实现。每件事都可以在CPU上实现。您正在等待任务完成,然后随机执行另一项任务。如果你想在CUDA中实现,你不需要等待所有的标志都是真的。你最初知道所有的标志都是假的。因此,只需为所有线程并行实现Do something
,并将标志更改为true。
如果您想在CUDA中实施,请在int flag
完成后继续Do something
并继续添加1,以便您可以在执行Do something
之前和之后了解标记的更改。< / p>
如果我的问题出错,请发表评论。我会尽力改善答案。