Уничтожение потоков CUDA и 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

Ответы на вопрос(1)

Решение Вопроса

Здесь есть две проблемы, обе связаны с деструктором вашего класса и областью видимости.

Во-первых, давайтеs начать с версии вашегоmain() который будет работать правильно:

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

    cudaDeviceReset();

    return 0;
}

Это работает правильно, потому что деструктор дляstreams вызывается ровно один раз (когдаstreams выпадает из области видимости), идо cudaDeviceReset называется.

Ваш оригиналmain() (или его компилируемая версия, но об этом позже ...) терпит неудачу по двум причинам. Позволять's посмотрим на это снова:

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

    cudaDeviceReset();

    return 0;
}

Здесь вы явно вызываете деструктор дляstreams (что вы почти никогда не должны делать), тоcudaDeviceResetто деструктор называетсяснова в ответном заявлении, когдаstreams выходит за рамки. Автоматический вызов деструктора после уничтожения контекста является источником ошибки / исключения.cudaStreamDestroy вызовы пытаются работать с потоками без действительного контекста CUDA. Таким образом, решение состоит в том, чтобы не иметь классов, которые делают вызовы API CUDA выпадающими из области видимости (или явно вызывают их деструкторы), когда нет контекста.

Если мы сделали третью версию как это:

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

    cudaDeviceReset();

    return 0;
}

Вы получите ошибку времени выполнения CUDA. Потому что деструктор получает вызовдважды, Первый раз (явный) это будет работать. Второе (имплицит, выходит за рамки) приведет к ошибке во время выполнения: у вас есть действительный контекст, но теперь вы пытаетесь уничтожить несуществующие потоки.

В качестве заключительного комментария / вопроса: насколько сложно было бы опубликовать и фактически скомпилированную версию кода, который вы показали в своем первоначальном вопросе? Буквально потребовалось 5 дополнительных строк, чтобы превратить это в правильный случай, когда кто-то еще мог скомпилировать и запустить. Я нахожу немного неразумным ожидать, что другие попытаются ответить на те вопросы, которые по сути являются отладочными, если вы не желаете прилагать аналогичные усилия для предоставления полезного кода и информации, которая делает всех ».жизнь намного проще. Думаю об этом. [конец напыщенной речи]

 JackOLantern07 июн. 2013 г., 14:35
Большое спасибо за ответ. Это хороший момент для инкапсуляции объектов класса в пределах их собственной области видимости.{}, Однако мне нужноstreams как глобальная переменная, потому что объект потока будет содержать также информацию оток" Stream, и мне нужно, чтобы он имел глобальную видимость запущенных ядер. Что я мог сделать в этом случае? Прошу прощения за воспроизводимость кода, это не было нежеланием, я просто упустил из виду. В следующий раз я выложу воспроизводимый код. Еще раз большое спасибо.
 JackOLantern07 июн. 2013 г., 16:55
Отлично. Итак, есть два правила: 1) Поместить объявления классов в другую область видимости {}cudaDeviceReset();; 2) Избегайте API CUDA внутри деструкторов. Большое спасибо еще раз. Теперь все, кажется, работает правильно.
 talonmies07 июн. 2013 г., 15:07
Очевидный ответ непоместить вызовы API CUDA в деструктор. В вашем классе у вас есть явный метод инициализациине вызывается через конструктор, так почему бы не использовать явный метод деинициализации? Таким образом, сфера становится не проблема

Ваш ответ на вопрос