44

例えば、cudaMalloc((void**)&device_array, num_bytes);

この質問は以前に尋ねられたもので、「エラーコードを返すため」という回答がありましたが、わかりcudaMallocません。ダブルポインタは、エラーコードを返すことと何の関係があるのでしょうか。なぜ単純なポインタがその仕事をすることができないのですか?

私が書いたら

cudaError_t catch_status;
catch_status = cudaMalloc((void**)&device_array, num_bytes);

エラーコードが入力さcatch_statusれ、割り当てられたGPUメモリへの単純なポインタを返すだけで十分ですよね。

4

3 に答える 3

72

C では、値またはシミュレートされた参照渡し(つまり、データへのポインター) を介して、データを関数に渡すことができます。値による方法は一方向の方法ですが、ポインターによる方法では、関数とその呼び出し環境の間で双方向のデータ フローが可能になります。

データ項目が関数パラメーター リストを介して関数に渡され、変更された値が呼び出し環境に表示されるように関数が元のデータ項目を変更することが期待される場合、これに対する正しい C メソッドはデータ項目を渡すことです。ポインタで。C では、ポインターで渡す場合、変更する項目のアドレスを取得してポインター (この場合はポインターへのポインター) を作成し、そのアドレスを関数に渡します。これにより、関数は呼び出し元の環境で (ポインターを介して) 元の項目を変更できます。

通常mallocはポインターを返します。呼び出し環境で割り当てを使用して、この戻り値を目的のポインターに割り当てることができます。の場合cudaMalloc、CUDA 設計者は、ポインタではなくエラー ステータスを運ぶために戻り値を使用することを選択しました。したがって、呼び出し環境でのポインターの設定は、参照によって (つまり、ポインターによって) 関数に渡されるパラメーターの 1 つを介して行われる必要があります。設定したいのはポインター値であるため、ポインターのアドレスを取得し (ポインターへのポインターを作成)、そのアドレスをcudaMalloc関数に渡す必要があります。

于 2012-10-17T14:54:07.247 に答える
9

ロバートの答えに追加しますが、最初に繰り返しますが、これは C API であり、参照をサポートしていないことを意味します。これにより、 function 内のポインターの値 (指されているものだけでなく) を変更できます。ロバート・クロヴェラによる答えはこれを説明しました。voidまた、C も関数のオーバーロードをサポートしていないため、そうする必要があることに注意してください。

さらに、C++プログラム内でC APIを使用する場合(ただし、これについては述べていません)、そのような関数をテンプレートでラップするのが一般的です。例えば、

template<typename T>
cudaError_t cudaAlloc(T*& d_p, size_t elements)
{
    return cudaMalloc((void**)&d_p, elements * sizeof(T));
}

上記のcudaAlloc関数を呼び出す方法には、次の 2 つの違いがあります。

  1. &呼び出し時にアドレス取得演算子 ( ) を使用したり、型にキャストしたりせずに、デバイス ポインターを直接渡しますvoid
  2. 2 番目の引数elementsは、バイト数ではなく要素数になりました。オペレーターはこれsizeofを容易にします。これは間違いなくより直感的に要素を指定でき、バイトを気にする必要はありません。

例えば:

float *d = nullptr;  // floats, 4 bytes per elements
size_t N = 100;      // 100 elements

cudaError_t err = cudaAlloc(d,N);      // modifies d, input is not bytes

if (err != cudaSuccess)
    std::cerr << "Unable to allocate device memory" << std::endl;
于 2015-05-23T16:47:23.617 に答える