并发写入相同的全局内存位置

时间:2011-05-10 17:28:22

标签: c++ c cuda

我有几个块,每个块在512的共享内存数组中有一些整数。如何检查每个块中的数组是否包含零作为元素?

我正在做的是创建一个驻留在全局内存中的数组。此数组的大小取决于块的数量,并初始化为0.因此,如果共享内存数组包含零,则每个块都会写入a[blockid] = 1

我的问题是当我在一个块中同时写入多个线程时。也就是说,如果共享内存中的数组包含多个零,则多个线程将写入a[blockid] = 1。这会产生任何问题吗?

换句话说,如果2个线程将完全相同的值写入全局内存中完全相同的数组元素,是否会出现问题?

4 个答案:

答案 0 :(得分:19)

对于CUDA程序,如果warp中的多个线程写入同一位置,则位置更新,但未定义 多少次< / em>位置已更新(即系列中发生了多少实际写入),未定义 线程将最后写入(即哪个线程将赢得比赛)。

对于计算能力为2.x的设备,如果warp中的多个线程写入同一地址,则只有一个线程实际执行写操作, 线程未定义。

来自CUDA C Programming Guide部分F.4.2:

  

如果warp执行的非原子指令写入warp的多个线程的全局内存中的同一位置,则只有一个线程执行写操作,而哪个线程执行该操作是未定义的。

有关详细信息,另请参阅本指南的第4.1节。

换句话说,如果写入给定位置的所有线程都写入相同的值,那么它是安全的。

答案 1 :(得分:13)

在CUDA执行模型中,无法保证从同一块中的线程到同一全局内存位置的每个同时写入都会成功。至少有一个写操作可以工作,但编程模型不能保证将发生多少写事务,或者如果执行多个事务,它们将以何种顺序发生。

如果这是一个问题,那么更好的方法(从正确的角度来看),就是每个块只有一个线程进行全局写操作。您可以使用原子设置的共享内存标志或还原操作来确定是否应设置该值。您选择哪个可能取决于可能存在多少个零。零越多,减少的吸引力就越大。 CUDA包括warp level __any()__all()运算符,可以在几行代码中构建一个非常有效的布尔减少。

答案 2 :(得分:1)

是的,这将是一个名为Race Condition的问题 您应该通过synchronizing

考虑process Semaphores对全局数据的访问权限

答案 3 :(得分:0)

虽然不是互斥锁或信号量,但CUDA确实包含一个可用于序列化对给定代码段或内存位置的访问的同步原型。通过__syncthreads()函数,您可以创建一个屏障,以便任何给定的线程在命令调用点处阻塞,直到给定块中的所有线程都执行了__syncthreads()命令。这样,您可以希望序列化对内存位置的访问,并避免两个线程需要同时写入同一内​​存位置的情况。唯一的警告是所有线程必须在某个时刻执行__syncthreads(),否则最终会出现死锁情况。因此,不要将调用置于某些条件if语句中,其中某些线程可能永远不会执行该命令。如果您确实像这样处理问题,则需要为最初不会调用__syncthreads()以便稍后调用该函数的线程做一些规定,以避免死锁。