ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – CUDA流销毁和CudaDeviceReset

2019-10-05 15:14:51  阅读:546  来源: 互联网

标签:c class cuda gpgpu nvidia


我使用CUDA流实现了以下类

class CudaStreams
{
    private:
        int             nStreams_;
        cudaStream_t*   streams_;
        cudaStream_t    active_stream_;

    public:

        // default constructor
        CudaStreams() { }

        // streams initialization
        void InitStreams(const int nStreams = 1) {
            nStreams_ = nStreams;
            // allocate and initialize an array of stream handles
            streams_ = (cudaStream_t*) malloc(nStreams_*sizeof(cudaStream_t));
            for(int i = 0; i < nStreams_; i++) CudaSafeCall(cudaStreamCreate(&(streams_[i]))); 

            active_stream_ = streams_[0];}

        // default destructor
        ~CudaStreams() {     
            for(int i = 0; i<nStreams_; i++) CudaSafeCall(cudaStreamDestroy(streams_[i])); }

}; 

如果我现在运行这个简单的代码

void main( int argc, char** argv) 
{
    streams.InitStreams(1);
    streams.~CudaStreams();

    cudaDeviceReset();
}

在cudaDeviceReset()调用之后,我收到以下消息:

test.exe中的未处理异常0x772f15de:0x00000000.

在使用cudaDeviceReset()时,在调用析构函数以避免此问题之前,我该怎么办?

编辑

如果我添加free(streams_);在析构函数中,即

~CudaStreams() {     
    for(int i = 0; i<nStreams_; i++) CudaSafeCall(cudaStreamDestroy(streams_[i])); // * 
    free(streams_); }

我收到以下错误消息

cudaSafeCall() failed at C:\Users\Documents\Project\Library\CudaStreams.cuh:79 : unknown error

其中第79行是析构函数中用*表示的.

此外,如果我在代码中直接使用构造函数和析构函数的相同指令,即

void main( int argc, char** argv) 
{
    int nStreams_ = 3;
    cudaStream_t* streams_ = (cudaStream_t*) malloc(nStreams_*sizeof(cudaStream_t));
    for(int i = 0; i < nStreams_; i++) CudaSafeCall(cudaStreamCreate(&(streams_[i]))); 
    for(int i = 0; i<nStreams_; i++) CudaSafeCall(cudaStreamDestroy(streams_[i])); 
    free(streams_);

cudaDeviceReset();
}

一切顺利. Perheps与课程的不良使用有关吗?

解决方法:

这里有两个问题,都与你的类和范围的析构函数有关.

首先,让我们从main()的一个版本开始,它将正常工作:

int main( int argc, char** argv) 
{
    {
        CudaStreams streams;
        streams.InitStreams(1);
    }

    cudaDeviceReset();

    return 0;
}

这是正确的,因为流的析构函数只调用一次(当流超出范围时),并且在调用cudaDeviceReset之前.

你原来的main()(或者它的可编译版本,但后来有更多关于它……)失败的原因有两个.让我们再看一遍:

int main( int argc, char** argv) 
{
    CudaStreams streams;
    streams.InitStreams(1);
    streams.~CudaStreams();

    cudaDeviceReset();

    return 0;
}

在这里你显式地调用了析构函数的流(你几乎不应该这样做),然后是cudaDeviceReset,然后当流超出范围时,在return语句中再次调用析构函数.在销毁上下文后自动调用析构函数是段错误/异常的来源. cudaStreamDestroy调用正在尝试在没有有效CUDA上下文的流上工作.所以解决方案是没有任何类在没有上下文时使CUDA API调用超出范围(或显式调用它们的析构函数).

如果我们制作了这样的第三个版本:

int main( int argc, char** argv) 
{
    {
        CudaStreams streams;
        streams.InitStreams(1);
        streams.~CudaStreams();
    }

    cudaDeviceReset();

    return 0;
}

您将收到CUDA运行时错误.因为析构函数会被调用两次.第一次(显式)它将起作用.第二个(隐含,超出范围)将产生运行时错误:您有一个有效的上下文,但现在正在尝试销毁不存在的流.

作为最终评论/问题:您在原始问题中显示的代码的发布和实际可编辑版本有多难?它确实需要5个额外的行来使它成为一个其他人可以实际编译和运行的适当的repro案例.我觉得如果你不愿意在提供有用的代码和信息方面做出类似的努力来让每个人的生活变得更加轻松,那么期望其他人努力回答基本上是调试问题的做法有点不合理.想一想. [咆哮结束]

标签:c,class,cuda,gpgpu,nvidia
来源: https://codeday.me/bug/20191005/1856630.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有