Cuda - 在__global__函数中打印来自对象的字符串

时间:2013-09-18 21:11:43

标签: string cuda global host

我是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;
    }
};

在这里,我正在调用Duomenys ::来自__global__函数:

__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;
}  

2 个答案:

答案 0 :(得分:3)

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

但是超出这个问题,大概是你从C ++标准库得到string。 (如果你展示一个完整的复制品代码,那就更好了,那么我不必猜测你得到的东西或你所包含的东西。)

如果我得到string如下:

#include <string>
using namespace std;

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

使用标准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;
}

请注意,我没有尝试理解您的代码或修复一些对我来说很奇怪的内容。然而,这应该证明一种可能的方法。

答案 1 :(得分:3)

您的问题不在于printf函数,而在于字符串数据类型。您不能在内核中使用C ++字符串类型。请在此处查看相关问题:Can we use the string data type in C++ within kernels