【发布时间】:2017-11-08 09:28:07
【问题描述】:
Win10 x64、CUDA 8.0、VS2015、6 核 CPU(12 个逻辑核心)、2 个 GTX580 GPU。
一般来说,我正在开发一个多线程应用程序,它启动与 2 个可用 GPU 相关联的 2 个线程,这些线程存储在线程池中。
每个线程在启动时都会执行以下初始化过程(即,这仅在每个线程的运行时执行):
::cudaSetDevice(0 or 1, as we have only two GPUs);
::cudaDeviceSetCacheConfig(cudaFuncCachePreferL1);
::cudaSetDeviceFlags(cudaDeviceMapHost | cudaDeviceScheduleBlockingSync);
然后,从其他工作线程(另外 12 个完全不接触 GPU 的线程)开始,我开始为这 2 个与 GPU 相关的工作线程提供数据,只要启动的 GPU 线程数量相等,它就可以完美运行到可用物理 GPU 的数量。
现在我想启动 4 个 GPU 线程(即每个 GPU 2 个线程)并让每个线程通过单独的 CUDA 流工作。我知道正确使用 CUDA 流所必需的要求,我满足所有这些要求。我失败的是上面提到的初始化过程。
一旦尝试从不同的 GPU 线程但对于同一个 GPU 执行此过程两次, ::cudaSetDeviceFlags(...) 就会开始失败,并显示 “当设备在此进程中处于活动状态时无法设置” 错误消息。
我查看了手册,似乎明白了发生这种情况的原因,但我不明白如何正确使用 ::cudaSetDeviceFlags(...) 进行设置。
我可以评论这条 ::cudaSetDeviceFlags(...) 行,即使每个 GPU 有 8 个线程,propgram 也能正常工作,但我需要设置 cudaDeviceMapHost 标志才能使用流,固定内存不会否则可用。
编辑要考虑的额外信息 #1:
- 如果在 ::cudaSetDevice 之前调用 ::cudaSetDeviceFlags 则不会出错 发生。
- 每个 GPU 线程通过以下方式分配一块固定内存 ::VirtualAlloc ->::cudaHostRegister 线程启动时的方法 (无论启动多少 GPU 线程都可以正常工作)和 在线程终止时释放它(通过 ::cudaHostUnregister -> ::虚拟免费)。 ::cudaHostUnregister 失败并显示“指针不 如果每个 GPU 的线程数大于 1,则对应于一半线程的已注册内存区域。
【问题讨论】:
-
你试过
cudaDeviceReset吗?您可以在设置标志之前按线程初始化调用它。但是你需要检查设备是否被其他线程使用,因为这个函数会立即重置设备。 -
明确地捕获并忽略错误不是最简单的事情吗?这意味着另一个线程已经按照您想要的方式设置了 GPU。我有 99% 的把握这个错误是良性的,只是你没有提供一个复制案例,我不会自己写一个。试试看
-
@Hamed:试过了,没有任何变化,同样的错误。
-
@Roman 使用您在评论中提供的这些新信息考虑 EDIT 您的问题,您可能会在那里得到更好的关注。
-
#1 无关紧要,如果您不进行 cudaSetDevice 调用,线程将不会附加到正确的上下文,也不会发生任何事情。 #2也几乎无关紧要。 GPU 上的上下文由生成它的线程拥有。如果该线程退出,则上下文将被销毁。任何其他尝试在同一个(现在是死上下文)上调用 API 的线程都会产生运行时错误。
标签: c++ multithreading cuda