CUDA中的忙等待

3
如何实现忙等待机制,示例如下:
while(variable == 0);

当某个CUDA线程在发生某些事件后将变量更新为1时。

我试图按照上面的方式编写代码,但是调用线程似乎完全忽略了它并且不等待。我非常确定该值为0,但线程根本不等待。 此外,如果我这样写:

while(variable == 0) __threadfence();

为了避免变量被缓存,即使变量最终被设置为1,该线程也会无限期地阻塞。对我来说,这一切都是非常奇怪的行为,因为在CPU上复制此代码会产生正确的行为。
编辑:奇怪的是,如果我每个块只有1个线程,则这似乎可以正常工作,但如果我在一个块中有几个线程,则不能看到同一块中的线程所做的写入,但可以看到来自其他块的线程所做的写入。奇怪...

可能最好包括定义“变量”的代码,因为它的声明可能导致它被缓存而不是在每次迭代中重新获取值。至少在 CPU 方面,这些类型或变量应该是“volatile”,但我对 CUDA 几乎一无所知,所以我不确定它的“volatile”是否表现相同。 - Necrolis
我的问题在于第一个代码示例中,即使变量为0,线程也从未阻塞。 - Tudor
3
在 https://dev59.com/zlzUa4cB1Zd3GeqPzQ17 中遇到了类似的问题。有一些讨论说明为什么在GPU上自旋锁不是一个好的选择。 - aland
你提出的问题确实有些启发,但并不完全。我仍然不明白为什么在不同的代码块之间使用这段代码会导致死锁,即使代码块的数量小于或等于核心数(意味着它们可以并发执行)。难道所有的代码块都能访问到全局内存吗? - Tudor
2
即使核心数大于块数,也不能保证块同时执行。 - Jared Hoberock
1个回答

8

忙等需要很多注意力,你必须非常小心!

你必须记住,32个线程组成一个warp并且完美同步工作。如果遇到分支,不参与的线程将被禁用,直到执行分支的线程退出。因此,尝试在warp内进行忙等可能会导致死锁:31个线程将永远等待单个禁用的线程完成其工作。

其次,如果你尝试在块之间同步,你必须知道两个块是同时运行的。理论上,你不知道有多少个块正在运行;在实践中,你可以读取GPU的规格,并启动它所能处理的数量(驱动程序和/或硬件存在一些错误,可能会导致一些问题)

第三,你必须记住CUDA编译器会尝试优化。你必须将共享或全局变量设置为“volatile”,以确保它始终被读取。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接