[英]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.