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());
} 

编辑:我正在尝试从文件中读取数据并将其打印在全局函数中。在这段代码中,我尝试读取所有数据并仅打印一个对象以查看是否一切正常。这是我得到的错误:

 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++ 字符串类型。在此处查看相关问题:我们可以在内核中使用 C++ 中的字符串数据类型吗

于 2013-09-18T22:49:08.690 回答
3

当格式说明符期待其他内容时,为什么要将string对象传递给?当我尝试在普通主机代码中执行此操作时,我收到有关“通过省略号传递非 POD 类型(调用将在运行时中止)”的警告。请注意,此问题与 CUDA 无关printf%s

但除此之外,大概您是string从 C++ 标准库中获得的。(如果您显示完整的复制器代码会更好,那么我不必猜测您从哪里得到东西或包含什么。)

如果我得到string如下:

#include <string>
using namespace std;

然后我使用 C++ 标准库中定义的函数。CUDA(大部分)支持 C++语言,但不一定支持在设备代码中使用 C++ 库(或 C 库)。库(通常)由(至少一些)编译后的代码(例如分配器,在这种情况下)组成,并且这些代码是为 CPU 编译的,而不是为 GPU 编译的。当你试图string在设备代码中使用这样的 CPU 编译例程(例如,与类关联的分配器)时,编译器会对你咆哮。如果您在问题中包含完整的错误消息,那么 (compiled-for-the-host) 函数实际上是什么问题会更加明显。

请改用标准 C 样式字符串(即char[],您将能够直接在printf.

编辑:针对评论中的问题,这里是发布的代码的修改版本,演示了如何使用普通的 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;
}

请注意,我并没有尝试理解您的代码或修复所有对我来说看起来很奇怪的东西。然而,这应该展示一种可能的方法。

于 2013-09-18T22:48:24.030 回答