生产者/消费者模型和并发内核
Posted
技术标签:
【中文标题】生产者/消费者模型和并发内核【英文标题】:producer/comsumer model and concurrent kernels 【发布时间】:2011-03-04 03:01:08 【问题描述】:我正在编写一个可以解释为生产者/消费者模型的 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
【问题讨论】:
【参考方案1】:由于您没有提供实际代码,因此很难检查错误在哪里。通常sceleton是正确的,但问题在于细节。
我能想到的可能问题之一:
默认情况下,在 CUDA 中,不能保证一个内核的全局内存写入对另一个内核可见,但原子操作除外。然后可能会发生您的第一个内核递增 PRODUCER_DONE,但 DATA 中仍然没有数据。
幸运的是,您获得了内部函数__threadfence()
,它会暂停当前线程的执行,直到数据可见。您应该将它放在以原子方式递增 PRODUCER_DONE 之前。查看 CUDA 编程指南中的第 B.5 章。
另一个可能出现也可能不会出现的问题:
从kernel2的角度来看,编译器可能会推断出PRODUCE_COUNT
,一旦读取,它就永远不会改变。编译器可以优化代码,以便一旦加载到寄存器中,它就可以重用它的值,而不是每次都查询全局内存。解决方案?使用volatile
,或使用另一个原子操作读取值。
(编辑) 第三期:
我忘了还有一个问题。在 pre-Fermi 卡(400 系列之前的 GeForce)上,您一次只能运行一个内核。因此,如果您安排生产者在消费者之后运行,系统将在生产者内核开始执行之前等待消费者内核结束。如果您希望两者同时运行,请将它们放入一个内核并基于某个块索引创建一个 if-branch。
【讨论】:
以上是关于生产者/消费者模型和并发内核的主要内容,如果未能解决你的问题,请参考以下文章
11.python并发入门(part8 基于线程队列实现生产者消费者模型)
python 复习—并发编程实战——多线程和多进程的生产者消费者模型线程进程再总结