在新线程中调用启用CUDA的库

时间:2011-07-15 15:17:39

标签: c++ multithreading cuda

我有一些代码,我已经编写并放入它自己的库中,使用CUDA在GPU上进行一些处理。

我正在使用Qt构建GUI前端,并且作为加载GUI的一部分,我调用

CUresult res;
CUdevice dev;
CUcontext ctx;

    cuInit(0);
    cuDeviceGet(dev,0);
    cuCtxCreate(ctx, 0, dev);

继续初始化GPU,以便在调用启用CUDA的库时应用程序尽可能响应。

问题是,我现在开始尝试从另一个线程调用我的CUDA库。

我是否必须付出一些努力才能做到这一点?另一个线程是唯一一个调用任何cuda函数的线程(调用cuInit()的主线程除外),但我的代码在我的cuda库中的cudaFree()调用中崩溃。

由于

4 个答案:

答案 0 :(得分:3)

上下文与创建它们的线程相关联。因此,您的两个选择是让GPU“工作线程”建立上下文,或者使用驱动程序API上下文迁移调用(cuCtxPopCurrentcuCtxPushCurrent)将上下文从线程移动到线程。请注意,上下文迁移不是免费的,因此如果您要做很​​多事情,您会发现GPU延迟会增加。

答案 1 :(得分:1)

我通常不使用驱动程序API,因此除了在cuCtxPopCurrent()cuCtxPushCurrent()之间容易混淆之外,我无法提供直接建议。

但绝对可以查看CUDA Toolkit 4.0 Readiness Tech Brief。 CUDA 4.0对多线程和多gpu的工作方式做了一些重大改动,值得一读。

答案 2 :(得分:1)

我过去使用的解决方案(Cuda 2.2)也是GPU“工作线程”范例,其中一个专用线程管理CUDA上下文。

可以在http://forums.nvidia.com/index.php?showtopic=66598

看到一种非常通用的方法(使用boost :: bind来转发函数调用)

链接中的示例代码:

GPUWorker gpu0(0);
GPUWorker gpu1(1);

// allocate data
int *d_data0;
gpu0.call(bind(cudaMalloc, (void**)((void*)&d_data0), sizeof(int)*N));
int *d_data1;
gpu1.call(bind(cudaMalloc, (void**)((void*)&d_data1), sizeof(int)*N));

// call kernel
gpu0.callAsync(bind(kernel_caller, d_data0, N));
gpu1.callAsync(bind(kernel_caller, d_data1, N));

GPUWorker对象通过call方法接受函数对象,这些函数对象被推送到队列中。然后GPUWorker :: run()将弹出函数对象并在适当的CUDA上下文中调用它们。

答案 3 :(得分:0)

如果要从其他线程而非创建Context的线程调用Cuda库,则必须从上下文创建线程中显式弹出Context(cuCtxPopCurrent(handle))并将返回的上下文句柄推到工作线程(cuCtxPushCurrent(* handle))。

在您的情况下,您可以在主线程中初始化Cuda设备,但是在工作线程中创建上下文,并且上下文将在创建后附加到工作线程。