在CUDA内核中填充数组或列表,但不在每个线程中填充

时间:2013-08-08 14:55:29

标签: c++ cuda

基本上,我的内核中有一个if(),如果条件已经验证,我想在动态列表或数组中存储一个新值。问题是我不能使用threadIdx,因为它不会在每个内核中填充。

类似的东西:

__global__ void myKernel(customType *c)
{
    int i = threadIdx.x;
    //whatever
    if(condition)
        c->pop(newvalue)
}

实际上我想避免ac [i] = newvalue因为最后我需要检查每个c [i]是否插入了一个值或者没有在主机代码中使用for循环并且正确地填充另一个结构体。 我想到了推力,但似乎对我的“简单”问题来说太过分了。

希望您能帮我找到解决方法。

2 个答案:

答案 0 :(得分:5)

如果我正确理解了您的问题,您有两种选择。

第一种方法是为每个线程预先分配一个输出位置,并且只有一些线程写入其输出。这将为您留下一个带有间隙的输出。您可以使用流压缩消除间隙,这是CUDA中已解决的问题 - 快速谷歌搜索将提供许多选项,并且Thrust和CUDPP都具有您可以使用的压缩功能。

第二种选择是使用全局内存计数器并让每个线程在输出流中使用位置时以原子方式递增计数器,如下所示:

unsigned int opos; // set to zero before call

__global__ void myKernel(customType *c)
{
    //whatever
    if(condition) {
        unsigned int pos = atomicAdd(&opos, 1);
        c[pos] = newval;
    }
}

如果您有Kepler卡,并且预期发出输出的线程数很少,则第二个选项可能会更快。如果不是这种情况,流压缩可能是更好的选择。

答案 1 :(得分:4)

如果我理解正确,你描述了一个流压缩。有些线程,而不是所有线程都会创建一个值,并且您希望将这些值存储在数组中而没有任何间隙。

实现此目的的一种方法是使用Thrust中提供的流压缩算法(请查看this example)。请注意,这确实需要您两次执行操作。

如果您是在单个线程块中(而不是整个网格)执行此操作,那么您还可以查看CUB。每个线程都会计算一个标志,指示它是否要存储一个值,对标志执行前缀和以确定列表中每个线程的偏移量,然后进行存储。