CUDA:在内核执行时从主机修改映射内存
我想在内核执行时修改主机上的一段映射内存,然后从内核中读取该值 我试着用下面的方法来做。我有这样一个内核:CUDA:在内核执行时从主机修改映射内存,c,windows,cuda,C,Windows,Cuda,我想在内核执行时修改主机上的一段映射内存,然后从内核中读取该值 我试着用下面的方法来做。我有这样一个内核: __global__ void kernel(int* d_ptr) { *d_ptr = 1; while( *d_ptr); } bool kernel_running = 0; __global__ void kernel(int* d_ptr) { *d_ptr = 1; while( *d_ptr) printf("%d\n", *d_ptr)
__global__ void kernel(int* d_ptr)
{
*d_ptr = 1;
while( *d_ptr);
}
bool kernel_running = 0;
__global__ void kernel(int* d_ptr)
{
*d_ptr = 1;
while( *d_ptr) printf("%d\n", *d_ptr);
}
void run( void* input )
{
int* h_ptr = (int*)input;
while( kernel_running)
{
*h_ptr = 0;
}
}
int main()
{
// HOST AND DEVICE POINTERS
int* h_ptr = 0;
int* d_ptr = 0;
// INITIALIZE POINTERS
assert( cudaHostAlloc(&h_ptr, sizeof(int), cudaHostAllocMapped) == cudaSuccess);
assert( cudaHostGetDevicePointer(&d_ptr, h_ptr, 0) == cudaSuccess);
// RUN KERNEL
kernel_running = 1;
_beginthread( run, 0, h_ptr);
kernel<<<1,1>>>(d_ptr);
assert( cudaDeviceSynchronize() == cudaSuccess);
kernel_running = 0;
}
d_ptr映射到可从主机访问的内存块
我还有一个像这样的主机线程
void run( void* input )
{
int* h_ptr = (int*)input;
while( kernel_running)
*h_ptr = 0;
}
__global__ void kernel(int* d_ptr)
{
*d_ptr = 1;
while( *d_ptr) printf("%d\n", *d_ptr);
}
因此,主机线程正在将0反复写入内核反复读取的位置,直到看到0为止。理论上,内核应该在读取主机线程写入的值后立即停止。问题是内核从未读取此0,因此它从未终止
奇怪的是,如果我像这样在内核中添加print语句
void run( void* input )
{
int* h_ptr = (int*)input;
while( kernel_running)
*h_ptr = 0;
}
__global__ void kernel(int* d_ptr)
{
*d_ptr = 1;
while( *d_ptr) printf("%d\n", *d_ptr);
}
然后它读取0并终止。我不知道发生了什么事。没有提供关于并发访问映射内存的太多信息,也很难找到解决这个问题的方法。有什么建议吗?我用的是Windows,我用的是编译
nvcc -g -arch=sm_20 -lineinfo
整个代码如下所示:
__global__ void kernel(int* d_ptr)
{
*d_ptr = 1;
while( *d_ptr);
}
bool kernel_running = 0;
__global__ void kernel(int* d_ptr)
{
*d_ptr = 1;
while( *d_ptr) printf("%d\n", *d_ptr);
}
void run( void* input )
{
int* h_ptr = (int*)input;
while( kernel_running)
{
*h_ptr = 0;
}
}
int main()
{
// HOST AND DEVICE POINTERS
int* h_ptr = 0;
int* d_ptr = 0;
// INITIALIZE POINTERS
assert( cudaHostAlloc(&h_ptr, sizeof(int), cudaHostAllocMapped) == cudaSuccess);
assert( cudaHostGetDevicePointer(&d_ptr, h_ptr, 0) == cudaSuccess);
// RUN KERNEL
kernel_running = 1;
_beginthread( run, 0, h_ptr);
kernel<<<1,1>>>(d_ptr);
assert( cudaDeviceSynchronize() == cudaSuccess);
kernel_running = 0;
}
bool内核运行=0;
__全局无效内核(int*d\u ptr)
{
*d_ptr=1;
而(*d_ptr)printf(“%d\n”,*d_ptr);
}
无效运行(无效*输入)
{
int*h_ptr=(int*)输入;
while(内核运行时)
{
*h_ptr=0;
}
}
int main()
{
//主机和设备指针
int*h_ptr=0;
int*d_ptr=0;
//初始化指针
断言(cudaHostAlloc(&h_ptr,sizeof(int),cudahostallocmap)=cudaSuccess);
断言(cudaHostGetDevicePointer(&d_ptr,h_ptr,0)=cudaSuccess);
//运行内核
内核运行=1;
_beginthread(run,0,h_ptr);
内核(d_ptr);
断言(cudaDeviceSynchronize()==cudaSuccess);
内核运行=0;
}
建议:
- 在调用
之前添加此项:cudaHostAlloc
报告提出了这一点cudaSetDeviceFlags(cudaDeviceMapHost);
- 将您的标志变量声明为volatile:
__global__ void kernel(volatile int* d_ptr)
#include <stdio.h>
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
exit(1); \
} \
} while (0)
__global__ void mykernel(volatile int *data){
while (*data) {};
printf("finished\n");
}
int main(){
int *d_data, *h_data;
cudaSetDeviceFlags(cudaDeviceMapHost);
cudaCheckErrors("cudaSetDeviceFlags error");
cudaHostAlloc((void **)&h_data, sizeof(int), cudaHostAllocMapped);
cudaCheckErrors("cudaHostAlloc error");
cudaHostGetDevicePointer(&d_data, h_data, 0);
cudaCheckErrors("cudaHostGetDevicePointer error");
*h_data = 1;
printf("kernel starting\n");
mykernel<<<1,1>>>(d_data);
cudaCheckErrors("kernel fail");
getchar();
*h_data = 0;
cudaDeviceSynchronize();
cudaCheckErrors("kernel fail 2");
return 0;
}
#包括
#定义cudaCheckErrors(msg)\
做{\
cudaError\u t\u err=cudaGetLastError()\
如果(_err!=cudaSuccess){\
fprintf(标准,“致命错误:%s(%s位于%s:%d)\n”\
msg,cudaGetErrorString(_err)\
__文件(行)\
fprintf(stderr,“***失败-中止\n”)\
出口(1)\
} \
}而(0)
__全局无效mykernel(volatile int*数据){
而(*数据){};
printf(“完成的”\n);
}
int main(){
int*d_数据,*h_数据;
cudaSetDeviceFlags(cudaDeviceMapHost);
cudaCheckErrors(“cudaSetDeviceFlags错误”);
cudaHostAlloc((void**)和h_数据,sizeof(int),cudaHostAllocMapped);
cudaCheckErrors(“cudaHostAlloc错误”);
cudaHostGetDevicePointer(&d_数据,h_数据,0);
cudaCheckErrors(“cudaHostGetDevicePointer错误”);
*h_数据=1;
printf(“内核启动\n”);
mykernel(d_数据);
cudaCheckErrors(“内核失败”);
getchar();
*h_数据=0;
cudaDeviceSynchronize();
cudaCheckErrors(“内核故障2”);
返回0;
}
谢谢你的回答!我试过你的代码,但是我的内核中*data的值在启动时是0,所以我没有复制1,因为某种原因…好的,我发现我在前面的评论中提到的问题是因为,因为我在Windows中使用WDDM驱动程序,内核直到cudaDeviceSynchronize()才启动,*h_data是零,这就是为什么我从内核直接读取零。。。我通过在内核调用之后立即触发早期启动来解决这个问题,如下所述: