1

私はcudaを初めて使用し、問題があります。スレッドに同期を入れたいので、syncthreadsを使用してみました。問題は、Visual Studio2010が次のように言っていることです。idetifier__syncthreads()は未定義です...ちなみに私はcuda4.2を使用しています。そこで、代わりにcudaDeviceSynchronize()を使用して、ホストから呼び出すことにしました。私のコードは上記のようなものです(私はあなたに重要な部分だけを送ります):

__global__ void sum( float avg[]){
  avg[0]+=1;
  avg[1]+=2;
}
int main(){
  float avg[2];
  float *devAvg;
  cudaError_t cudaStatus;
  size_t size=sizeof(unsigned char)*2;
  cudaStatus = cudaMalloc((void**)&devAvg, size2);
  if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMalloc 2 failed!");
    return -1;
  }
  avg[0]=0;
  avg[1]=0;
  cudaStatus = cudaMemcpy(devAvg,avg, size, cudaMemcpyHostToDevice);
  if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMemcpy failed!");
    return -1;
  }
  dim3 nblocks(40,40);
  dim3 nthreads(20,20);
  sum<<<nblocks,nthreads,msBytes>>>(devAvg);
  cudaStatus = cudaDeviceSynchronize();
  if (cudaStatus != cudaSuccess) {
      fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
  }

  cudaStatus = cudaMemcpy(avg,devAvg,size,cudaMemcpyDeviceToHost);
  if (cudaStatus != cudaSuccess) {
      fprintf(stderr, "cudaMemcpy Device to Host failed!");
      return -1;}
  cout<<"avg[0]="avg[0]<<" avg[1]="<<avg[1]<<endl;
  cudaFree devAvg;
  return 0;
  }

結果はavg[0]= 640.000 avg [1]=1.280.000になるはずだと思いました

しかし、私の結果が異なるだけでなく(これはオーバーフローの問題である可能性があります)、安定していません。たとえば、3つの異なる実行の場合、結果は次のようになります。

avg [0] = 3041 avg [1] = 6604

avg [0] = 3015 avg [1] = 6578

avg [0] = 3047 avg [1] = 6600

では、ここで何が間違っているのでしょうか?それは同期の問題ですか?そしてなぜ__syncthreads()を使用できないのですか?それとも競合状態の問題ですか?

さらに、__ syncthreads()の問題については、私が書いたコードが付属しています。最も単純なものでさえ:

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <Windows.h>


// Kernel that executes on the CUDA device
__global__ void square_array(float *a, int N)
{
  int idx = blockIdx.x * blockDim.x + threadIdx.x;
  if (idx<N) a[idx] = a[idx] * a[idx];
  __syncthreads();
}

// main routine that executes on the host
int main(void)
{
  float *a_h, *a_d;  // Pointer to host & device arrays
  const int N = 10;  // Number of elements in arrays
  size_t size = N * sizeof(float);
  a_h = (float *)malloc(size);        // Allocate array on host
  cudaMalloc((void **) &a_d, size);   // Allocate array on device
  // Initialize host array and copy it to CUDA device
  for (int i=0; i<N; i++) a_h[i] = (float)i;
  cudaMemcpy(a_d, a_h, size, cudaMemcpyHostToDevice);
  // Do calculation on device:
  int block_size = 4;
  int n_blocks = N/block_size + (N%block_size == 0 ? 0:1);
  square_array <<< n_blocks, block_size >>> (a_d, N);
  // Retrieve result from device and store it in host array
  cudaMemcpy(a_h, a_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
  // Print results
  for (int i=0; i<N; i++) printf("%d %f\n", i, a_h[i]);
  // Cleanup
  free(a_h); cudaFree(a_d);
      return 0;
}

これは次のように言っています:エラー:識別子 "__syncthreads()"は未定義です

面白い部分は、4.2 CUDA SDKに付属しているサンプルコードでも同じことが起こることです...SDKサンプルには未定義と見なされる関数が多いため、おそらくもっと一般的な間違いです。

4

1 に答える 1

5

スレッドのすべてのブロックが同じ 2 つの場所に書き込んでいます。これを適切に機能させる唯一の方法は、アトミック操作を使用することです。それ以外の場合、スレッドが場所を読み取り、追加し、結果を場所に「同時に」書き戻す結果は未定義です。

カーネルを次のように書き換えると:

__global__ void sum( float avg[]){
   atomicAdd(&(avg[0]),1);
   atomicAdd(&(avg[1]),2);
}

表示されている問題を解決する必要があります。

__syncthreads() に関する質問に答えるには、コンパイラ エラーの原因となった正確なコードを確認する必要があります。あなたがそれを投稿した場合、私は私の答えを更新します。このカーネルに __syncthreads() 呼び出しを挿入しても問題はありませんが、表示されている問題は修正されません。

C プログラミング ガイドのアトミック操作のセクションを確認することをお勧めします。

アトミックを使用すると、一般にコードの実行が遅くなるため、注意して使用する必要があります。ただし、この学習演習では、問題を解決する必要があります。

また、投稿したコードは正常にコンパイルされず、多くの定義が欠落しており、コードにはさまざまな問題があることにも注意してください。しかし、結果を投稿しているので、投稿していなくても、これが機能しているバージョンがあると思います。したがって、投稿したコードのすべての問題を特定したわけではありません。

これは、さまざまなコーディングの問題がすべて修正された、あなたのものに似たコードであり、私にとってはうまくいくようです:

#include <stdio.h>
#include <iostream>

#define msBytes 0

__global__ void sum( float avg[]){
  atomicAdd(&(avg[0]),1);
  atomicAdd(&(avg[1]),2);
}
int main(){
  float avg[2];
  float *devAvg;
  cudaError_t cudaStatus;
  size_t size=sizeof(float)*2;
  cudaStatus = cudaMalloc((void**)&devAvg, size);
  if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMalloc 2 failed!");
    return -1;
  }
  avg[0]=0;
  avg[1]=0;
  cudaStatus = cudaMemcpy(devAvg,avg, size, cudaMemcpyHostToDevice);
  if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMemcpy failed!");
    return -1;
  }
  dim3 nblocks(40,40);
  dim3 nthreads(20,20);
  sum<<<nblocks,nthreads,msBytes>>>(devAvg);
  cudaStatus = cudaDeviceSynchronize();
  if (cudaStatus != cudaSuccess) {
      fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
  }

  cudaStatus = cudaMemcpy(avg,devAvg,size,cudaMemcpyDeviceToHost);
  if (cudaStatus != cudaSuccess) {
      fprintf(stderr, "cudaMemcpy Device to Host failed!");
      return -1;}
  std::cout<<"avg[0]="<<avg[0]<<" avg[1]="<<avg[1]<<std::endl;
  cudaFree(devAvg);
  return 0;
  }

実行すると、次の出力が得られます。

avg[0]=640000 avg[1]=1.28e+06

また、 foratomicAddを で使用できるようにfloatするには、コンピューティング機能 2.0 以上のデバイスが必要です (また、-arch=sm_20その種類のデバイス用にコンパイルするためにコンパイラ スイッチを渡す必要があります)。以前のデバイス (コンピューティング機能 1.x) を使用している場合は、 avg[] を のint代わりにas として定義する同様のプログラムを作成できますfloat。または、必要に応じて、「ただし、atomicCAS() (比較スワップ)」。

于 2012-12-12T17:08:42.080 に答える