在每个主机线程(多线程CPU)上创建一个CUDA流

5
我有一台多线程CPU,希望每个CPU线程都能够启动一个单独的CUDA流。这些独立的CPU线程会在不同的时间做不同的事情,因此有可能它们不会重叠,但如果它们同时启动一个CUDA内核,我希望它们能够继续并发运行。
我相信这是可能的,因为在CUDA Toolkit文档的3.2.5.5节中指出:“流是一系列命令(可能由不同的主机线程发出)…”。因此,如果我想要实现这一点,我需要做如下操作:
void main(int CPU_ThreadID) {
    cudaStream_t *stream;
    cudaStreamCreate(&stream);

    int *d_a;
    int *a;
    cudaMalloc((void**)&d_a, 100*sizeof(int));
    cudaMallocHost((void**)&a, 100*8*sizeof(int));
    cudaMemcpyAsync(d_a, a[100*CPU_ThreadID], 100*size(int), cudaMemcpyHostToDevice, stream);
    sum<<<100,32,0,stream>>>(d_a);

    cudaStreamDestroy(stream);
}

这只是一个简单的示例。如果我知道只有8个CPU线程,则最多会创建8个流。这是正确的方法吗?如果两个或更多不同的主机线程在大约相同时到达此代码,它是否会并发运行?感谢任何帮助!

编辑:

我纠正了代码块中的一些语法问题,并像sgar91建议的那样放入了cudaMemcpyAsync。


1
您不必为stream指针分配内存。此外,如果您希望流重叠,可以考虑使用cudaMemcpyAsync - sgarizvi
@sgar91:这些流会在不同的上下文中,因此它们将永远不会重叠。 - talonmies
@sgar91 谢谢!我已经进行了上述编辑。对于talonmies:那么没有办法让单独的CPU线程同时访问GPU设备吗?像Robert Crovella在下面建议的强制线程使用相同的上下文怎么样? - Miggy
1个回答

3
我认为您提出的是一个多进程应用程序而不是多线程的。您没有提及所考虑的线程架构或操作系统,但我知道的线程架构并没有设定一个名叫“main”的线程程序,并且您也没有展示关于线程代码的任何前置内容。
多进程环境通常会为每个进程创建一个设备上下文,这将抑制细粒度并发。
即使这只是一个疏忽,我也要指出,一个多线程应用程序应在线程生成之前在所需设备上建立GPU上下文。
然后每个线程都可以发出cudaSetDevice(0);或类似的调用,这应该会使每个线程挑选已建立在指定设备上的上下文。
一旦这样做了,您就可以从任何线程向所需流发出命令。
您可能需要参考cudaOpenMP示例代码。尽管它省略了流概念,但它演示了具有多个线程向同一设备发出命令的潜力的多线程应用程序(并且可以扩展到同一流)。
无论在解决上述问题后内核是否同时运行都是一个分开的问题。并行内核执行有许多要求,并且内核本身必须具有兼容的资源要求(块、共享内存、寄存器等),这通常意味着“小”内核。

谢谢你的回答。我非常确定它是多线程的,因为构建应用程序的程序员说过。我不确定,因为我没有构建它。尽管如此,它是一个图像处理算法,我知道在我们的8核CPU(超线程到16个线程)上,它一次处理15张图片(一个线程保留来管理作业)。我使用Windows操作系统。主要名称只是我在.cu文件中调用内核的函数的名称,它可以被称为任何名称。我将尝试您的建议和示例,然后再回来。再次感谢。对于我的困惑,我很抱歉。 - Miggy
抱歉我花了这么长时间才接受。我被迫搁置了这个项目。我按照你的建议,使用cudaOpenMP示例代码作为范例来完成了。我创建了一个C#程序,使用System.Threading创建不同的CPU线程,每个线程通过我的Cuda dll启动一个内核。我使用NVIDIA Visual Profiler进行了测试,可以验证它们在同一Cuda上下文中作为不同流并行运行。我需要使用的主程序不是通过System.Threading创建线程,而是使用另一种方法,所以我还不确定是否解决了我的问题,但你让我走上了正确的轨道。谢谢! - Miggy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接