0


我正在编写一个可以解释为生产者/消费者模型的 cuda 程序。

有两个内核,一个在设备内存上
产生数据,另一个内核产生数据。

消耗线程的数量设置为 32 的倍数,即经纱大小的两倍。
并且每个 warp 等待直到 32 个数据已经产生。

我这里有点问题。
如果消费者内核的加载时间晚于生产者内核,
则程序不会停止。
即使首先加载了消费者,该程序有时也会不确定地运行。

我要问的是 CUDA 中是否有一个很好的生产者/消费者实现模型?
任何人都可以给我一个方向或参考吗?

这是我的代码的骨架。

**kernel1**:

while LOOP_COUNT
    compute something
    if SOME CONDITION
        atomically increment PRODUCE_COUNT          
        write data into DATA            
atomically increment PRODUCER_DONE

**kernel2**:
while FOREVER
    CURRENT=0
    if FINISHED CONDITION
        return
    if PRODUCER_DONE==TOTAL_PRODUCER && CONSUME_COUNT==PRODUCE_COUNT
        return
    if (MY_WARP+1)*32+(CONSUME_WARPS*32*CURRENT)-1 < PRODUCE_COUNT
        process the data
        if SOME CONDITION
            set FINISHED CONDITION true
        increment CURRENT
    else if PRODUCUER_DONE==TOTAL_PRODUCER
        if currnet*32*CONSUME_WARPS+THREAD_INDEX < PRODUCE_COUNT
            process the data
            if SOME CONDITION
                set FINISHED CONDITION true
            increment CURRENT
4

1 回答 1

2

由于您没有提供实际代码,因此很难检查错误在哪里。通常sceleton是正确的,但问题在于细节。

我能想到的可能问题之一:

默认情况下,在 CUDA 中,不能保证一个内核的全局内存写入对另一个内核可见,但原子操作除外。然后可能会发生您的第一个内核递增 PRODUCER_DONE,但 DATA 中仍然没有数据。

幸运的是,您获得了__threadfence()停止当前线程执行的内在函数,直到数据可见。您应该将它放在以原子方式递增 PRODUCER_DONE 之前。查看 CUDA 编程指南中的第 B.5 章。

另一个可能出现也可能不会出现的问题:

从 kernel2 的角度来看,编译器可能会推断,PRODUCE_COUNT一旦读取,它就永远不会改变。编译器可以优化代码,以便一旦加载到寄存器中,它就可以重用它的值,而不是每次都查询全局内存。解决方案?使用volatile,或使用另一个原子操作读取值。

(编辑) 第三期:

我又忘记了一个问题。在 pre-Fermi 卡(400 系列之前的 GeForce)上,您一次只能运行一个内核。因此,如果您安排生产者在消费者之后运行,系统将在生产者内核开始执行之前等待消费者内核结束。如果您希望两者同时运行,请将它们放入单个内核并具有基于某个块索引的 if 分支。

于 2011-03-04T06:42:13.417 回答