在Cuda中使用锁定示例点积

时间:2016-03-20 22:35:17

标签: c++ cuda

我正在阅读这本书"Cuda by Example" by Jason Sanders and Edward Kandrot并且有一个关于他们使用锁来计算两个数组的点积的问题(见链接pdf的第254-258页)。他们定义了他们的lock.h头文件:

#ifndef __LOCK_H__
#define __LOCK_H__


struct Lock{
    int *mutex;
    Lock(){
        int state = 0;
        cudaMalloc((void**)&mutex, sizeof(int));
        cudaMemcpy(mutex, &state, sizeof(int), cudaMemcpyHostToDevice);
    }

    ~Lock(){
        cudaFree(mutex);
    }

    __device__ void lock(){
        while (atomicCAS(mutex, 0 ,1) != 0);
    }

    __device__ void unlock(){
        atomicExch(mutex, 0);
    }
};


#endif
然后他们将他们的点产品内核称为:

int main()
{
    // bunch of code, initialization etc

    Lock lock;
    dot<<<blocksPerGrid,threadsPerBlock>>>(lock, dev_a, dev_b, dev_c);

    // more code, frees, etc
} 

点内核声明为:

__global__ void dot(Lock lock, float *a, float *b, float *c);

这是否会创建无效的free,因为Lock结构不包含复制构造函数?我们通过值传递锁定,它只是按值复制互斥锁指针。当我们退出内核时,析构函数在这个互斥锁指针上调用cudaFree。当我们退出main函数时,然后我再次调用析构函数,但是现在mutex已经被释放了!我问,因为在一个不同的更大的代码中,我使用同样的想法时得到cudeErrorInvalidDevicePointer错误,我认为问题是没有复制构造函数。

1 个答案:

答案 0 :(得分:1)

是的,你是对的,还会打一个额外的电话 - 你也可以自己查一下......

以下是验证的简单示例:

#include <iostream>
#include <cuda_runtime.h>

struct A {
    A()  { std::cout << "ctor for " << this << std::endl << std::flush; }
    ~A() { std::cout << "dtor for " << this << std::endl << std::flush; }
};

__global__ void foo(A device_a) { }

int main(void) {
    A host_a;
    foo<<<1,1>>>(host_a);
    cudaDeviceReset();
    return 0;
}

输出是:

ctor for 0x7ffe584c85bf
dtor for 0x7ffe584c85df
dtor for 0x7ffe584c85bf

所以,你得到了默认的拷贝ctor;并且两个副本的构造和销毁发生在主机上(这些是仅限主机的功能,而设备没有<iostream>)。我实际上发现有点奇怪,但我想这是CUDA的“C-ish”起源的一部分,处理像POD这样的内核参数。看到ctors和dtors如何获得__device____host__限定符,这一点尤为令人惊讶。

但是,在该示例中额外调用cudaFree()应该不是问题(手指交叉):CUDA Runtime API手册第3.9节说调用应该失败并返回cudaErrorInvalidDevicePointer

尽管如此,这种糟糕的编程习惯和结构应该以不同的方式编写IMO。