CUDA:在内核执行时修改主机的映射内存

时间:2013-11-24 05:03:41

标签: c windows cuda

我想从内核正在执行的主机上修改一段映射内存,然后从内核中读取该值。

我正在尝试以下方式执行此操作。我有这样的内核:

__global__ void kernel(int* d_ptr)
{
    *d_ptr = 1;
    while( *d_ptr);
}

d_ptr映射到可从主机访问的内存。

我也有一个看起来像这样的主机线程

void run( void* input )
{
    int* h_ptr = (int*)input;
    while( kernel_running)
        *h_ptr = 0;
}

因此,主机线程重复地将0写入内核重复读取的位置,直到它看到0.理论上,内核应该在读取主机线程写入的值后立即停止。问题是内核永远不会读取此0,因此它永远不会终止。

奇怪的是,如果我在内核中添加一个print语句,就像这样

__global__ void kernel(int* d_ptr)
{
    *d_ptr = 1;
    while( *d_ptr) printf("%d\n", *d_ptr);
}

然后它会读取0并终止。我不知道发生了什么。 cuda programming guide没有提供有关对映射内存的并发访问的大量信息,并且很难找到解决此问题的问题。有什么指针吗?我正在使用Windows,而我正在使用

进行编译
nvcc -g -arch=sm_20 -lineinfo

整个代码如下所示:

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;
}

1 个答案:

答案 0 :(得分:0)

建议:

  • 在致电cudaHostAlloc之前添加此内容:

    cudaSetDeviceFlags(cudaDeviceMapHost);
    

    documentation暗示了这一点。

  • 将您的标志变量声明为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;
}