2011-03-04 73 views
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 

回答

2

既然你没有提供一个实际的代码,这是很难检查哪里出了错误。通常情况是正确的,但问题在于细节。

其中之一,我能想到的可能的问题:

默认情况下,在CUDA没有保证全局存储器由一个内核写入将是可见的另一个核心,以原子操作的一个例外。那么可能发生的情况是,您的第一个内核增加了PRODUCER_DONE,但DATA中仍然没有数据。

幸运的是,您将获得内在函数__threadfence(),它会暂停当前线程的执行,直到数据可见。您应该在自动递增PRODUCER_DONE之前放置它。查阅CUDA编程指南中的章节B.5。

可能可能不显示或另一个问题:从视图kernel2点

,编译器可以扣除PRODUCE_COUNT,曾经看过,它永远不会改变。编译器可以优化代码,以便一旦加载到寄存器中,它就会重新使用它的值,而不是每次查询全局内存。解?使用volatile,或使用另一个原子操作读取该值。

(编辑) 第三个问题:

我忘了一个多问题。在费米卡之前(400系列之前的GeForce),您一次只能运行一个内核。因此,如果您安排生产者在消费者之后运行,那么在生产者内核开始执行之前,系统将等待消费者内核结束。如果你想让它们同时运行,那么把它们放到一个单独的内核中,并且根据一些块索引设置一个if-branch。

+0

谢谢你的回答! – superscalar 2011-03-04 07:00:59