簡體   English   中英

CUDA流破壞和CudaDeviceReset

[英]CUDA streams destruction and CudaDeviceReset

我已經使用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();
}

一切正常。 偷窺與某班的不良使用有關嗎?

這里有兩個問題,都與類和作用域的析構函數有關。

首先,讓我們從可以正常運行的main()版本開始:

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

    cudaDeviceReset();

    return 0;
}

之所以能夠正常工作,是因為streams的析構函數只被調用一次(當streams超出范圍時),並且 cudaDeviceReset 之前

原始的main() (或它的可編譯版本,但稍后會詳細介紹...)由於兩個原因而失敗。 讓我們再來看一看:

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

    cudaDeviceReset();

    return 0;
}

在這里,您顯式地調用streams的析構函數(您幾乎應該永遠不要這樣做),然后cudaDeviceReset ,然后在streams超出范圍時在return語句中再次調用析構函數。 上下文被破壞后自動調用析構函數是segfault / exception的來源。 cudaStreamDestroy調用試圖在沒有有效CUDA上下文的流上工作。 因此,解決方案是在沒有上下文的情況下,沒有任何使CUDA API調用超出范圍(或顯式調用其析構函數)的類。

如果我們制作了第三個這樣的版本:

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

    cudaDeviceReset();

    return 0;
}

您將收到CUDA運行時錯誤。 因為析構函數兩次被調用。 第一次(顯式)它將起作用。 第二個(隱式,超出范圍)將產生運行時錯誤:您具有有效的上下文,但是現在正嘗試銷毀不存在的流。

作為最后的評論/問題:發布和顯示原始問題中的代碼的實際可編譯版本有多困難? 從字面上看,它需要5條額外的行才能使其成為其他人可以實際編譯並運行的適當復制實例。 如果您不願意付出類似的努力來提供有用的代碼和信息,而這又使每個人的生活變得更加輕松,那么我期望其他人做出努力來回答基本上是調試問題的想法有點不合理。 想一想。 [結束語]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM