0

私はCUDAを初めて使用し、奇妙なエラーが発生しています。渡されたオブジェクトから文字列を出力したいのですが、「グローバル関数からのホスト関数の呼び出しは許可されていません」というエラーが表示され、その理由がわかりません。しかし、整数を出力したい場合 (get メソッドを sk1 を返すように変更)、すべて正常に動作します。コードは次のとおりです。

class Duomenys {   
private:
   string simb;
   int sk1;
   double sk2;
 public:
      __device__ __host__ Duomenys(void): simb(""), sk1(0), sk2(0.0) {}
      __device__ __host__~Duomenys() {} 

    __device__ __host__ Duomenys::Duomenys(string simb1, int sk11, double sk21)
              : simb(simb1), sk1(sk11), sk2(sk21) {}

    __device__ __host__ string Duomenys::get(){
        return simb;
    }
};

ここで、__global__ 関数から Duomenys::get を呼び出しています。

__global__ void Vec_add(Duomenys a) {   
     printf(" %s \n",a.get());
} 

編集:ファイルからデータを読み取り、グローバル関数で印刷しようとしています。このコードでは、すべてのデータを読み取り、1 つのオブジェクトだけを出力して、すべてが機能するかどうかを確認しようとしています。これは私が得ているエラーです:

 calling a __host__ function("std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string") from a __global__ function("Vec_add") is not allowed  

コード:

#include <stdio.h>
#include <stdlib.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <vector>  
#include <string> 
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <sstream>

using namespace std;

class Duomenys {   
private:
   string simb;
   int sk1;
   double sk2;
 public:
      __device__ __host__ Duomenys(void): simb(""), sk1(0), sk2(0.0) {}
      __device__ __host__~Duomenys() {} 

    __device__ __host__ Duomenys::Duomenys(string simb1, int sk11, double sk21)
              : simb(simb1), sk1(sk11), sk2(sk21) {}

    __device__ __host__ string Duomenys::print()
    {
        stringstream ss;
        ss << left << setw(10) << simb << setw(10) << sk1 << setw(10) << sk2;
        return ss.str();
    }
};

__global__ void Vec_add(Duomenys a) {

     printf(" %s \n",a.print());
}  


/* Host code */
int main(int argc, char* argv[]) {

   setlocale (LC_ALL,"");
    vector<Duomenys> vienas;
    vector<vector<Duomenys>> visi;

    //data reading to vector "vienas" (it works without any errors)

    Duomenys *darr;
    const size_t sz = size_t(2) * sizeof(Duomenys);
    cudaMalloc((void**)&darr, sz);
     Vec_add<<<1, 1>>>(visi[0].at(0));
     cudaDeviceSynchronize();
     cudaMemcpy(darr, &visi[0].at(0), sz, cudaMemcpyHostToDevice);

   return 0;
}  
4

2 に答える 2

4

問題は printf 関数ではなく、文字列データ型にあります。カーネルでは C++ 文字列型を使用できません。ここで関連する質問を参照してください: Can we use the string data type in C++ within kernels

于 2013-09-18T22:49:08.690 に答える
3

フォーマット指定子が何か他のものを期待しているのに、なぜstringオブジェクトを渡すのでしょうか? 通常のホスト コードでこれを実行しようとすると、「POD 以外の型を省略記号で渡す (呼び出しは実行時に中止されます)」という警告が表示されます。この問題はCUDA とは何の関係もないことに注意してください。printf%s

しかし、その問題を超えて、おそらくstringC++ 標準ライブラリから取得しています。(完全なリプリケータ コードを表示する方がよいでしょう。そうすれば、どこで何を取得しているのか、何を含めているのかを推測する必要がなくなります。)

次のようになった場合string

#include <string>
using namespace std;

次に、C++ 標準ライブラリで定義されている関数を使用しています。CUDA は C++言語を(ほとんど) サポートしていますが、デバイス コードでの C++ ライブラリ (または C ライブラリ) の使用を必ずしもサポートしているわけではありません。ライブラリは (通常) (少なくとも一部の) コンパイル済みコード (この場合はアロケーターなど) で構成されており、このコードは GPU 用ではなく CPU 用にコンパイルされています。このような CPU でコンパイルされたルーチン (クラスに関連付けられたアロケータなどstring) をデバイス コードで使用しようとすると、コンパイラが吠えます。質問に完全なエラー メッセージを含めると、具体的にどの (ホスト用にコンパイルされた) 関数が実際に問題であるかがより明確になります。

代わりに、標準の C スタイルの文字列char[]を使用します (つまり、printf.

EDIT : コメントの質問に答えて、投稿されたコードの修正版を次に示します。これは、通常の C スタイルの文字列 (つまりchar[]) を使用してデバイス コードで出力する方法を示しています。

#include <stdio.h>
#include <stdlib.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <sstream>
#define STRSZ 32
using namespace std;

class Duomenys {
private:
   char simb[STRSZ];
   int sk1;
   double sk2;
 public:
      __device__ __host__ Duomenys(void):  sk1(0), sk2(0.0) {}
      __device__ __host__~Duomenys() {}

    __device__ __host__ Duomenys(char  *simb1, int sk11, double sk21)
              :  sk1(sk11), sk2(sk21) {}

    __device__ __host__ char * print()
    {
        return simb;
    }
    __device__ __host__ void store_str(const char *str)
    {
    for (int i=0; i< STRSZ; i++)
      simb[i] = str[i];
    }
};

__global__ void Vec_add(Duomenys a) {

     printf(" %s \n",a.print());
}


/* Host code */
int main(int argc, char* argv[]) {

    string host_string("hello\n");
    setlocale (LC_ALL,"");
    vector<Duomenys> vienas(3);
    vienas[0].store_str(host_string.c_str());
    vector<vector<Duomenys> > visi(3);
    visi[0] = vienas;

    //data reading to vector "vienas" (it works without any errors)

    Duomenys *darr;
    const size_t sz = size_t(2) * sizeof(Duomenys);
    cudaMalloc((void**)&darr, sz);
    Vec_add<<<1, 1>>>(visi[0].at(0));
    cudaDeviceSynchronize();
    cudaMemcpy(darr, &(visi[0].at(0)), sz, cudaMemcpyHostToDevice);

    return 0;
}

あなたのコードを理解しようとしたり、奇妙に見えるすべてを修正しようとしたりしていないことに注意してください。ただし、これは 1 つの可能なアプローチを示す必要があります。

于 2013-09-18T22:48:24.030 に答える