我正在编写一个可以解释为生产者/消费者模型的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
答案 0 :(得分:2)
由于您没有提供实际代码,因此很难检查错误的位置。通常情节是正确的,但问题在于细节。
我能想到的一个可能的问题:
默认情况下,在CUDA中,不能保证一个内核写入的全局内存将被另一个内核可见,原子操作除外。然后,您的第一个内核会增加PRODUCER_DONE,但DATA中仍然没有数据。
幸运的是,您将获得内部函数__threadfence()
,它会暂停当前线程的执行,直到数据可见。您应该在原子递增PRODUCER_DONE之前将其放入。查看CUDA编程指南中的B.5章节。
可能出现或未出现的另一个问题:
从kernel2的角度来看,编译器可能会扣除PRODUCE_COUNT
,一旦读取,它就永远不会改变。编译器可以优化代码,以便一旦加载到寄存器中,它就会重用其值,而不是每次都查询全局内存。解?使用volatile
,或使用其他原子操作读取值。
(编辑) 第三期:
我忘记了另外一个问题。在前费米卡(400系列之前的GeForce)上,您一次只能运行一个内核。因此,如果您将生产者安排在使用者之后运行,系统将等待使用者内核在生产者内核开始执行之前结束。如果您希望两者同时运行,请将两者放入单个内核并根据某些块索引具有if分支。