Пример cuda atomicAdd не может дать правильный вывод

Следующий код был написан с целью увеличения массива из 100 элементов с плавающей запятой в 1 десять раз. В выводе я ожидал массив из 100 элементов со значением 10.0f для каждого элемента. Вместо этого я получаю случайные значения. Можете ли вы указать мою ошибку здесь?

__global__  void testAdd(float *a)
{
    float temp;
    for (int i = 0; i < 100 ; i++)
    {
        a[i] = atomicAdd(&a[i], 1.0f);
    }
}
void cuTestAtomicAdd(float *a)
{
    testAdd<<<1, 10>>>(a);
}

Моя цель состоит в том, чтобы понять работу атомных операций, чтобы применить их в другом месте.

1 ответ

Решение

Это не так, как мы делаем atomicAdd операция.

Просто сделайте это так:

atomicAdd(&a[i], 1.0f);

и рассматриваемая переменная (a[i]) будет обновлено.

Возвращаемое значение из атомарной функции обычно является старым значением, которое было в переменной, до атомарного обновления.

Делая это:

a[i] = atomicAdd(&a[i], 1.0f);

обновит переменную a[i], а затем (не атомарно) назначить старое значение переменной a[i], Это почти наверняка не то, что вы хотите.

Прочитайте документацию:

Функция возвращает старую.

Следующий полный код демонстрирует правильное использование:

#include <iostream>

__global__  void testAdd(float *a)
{
    for (int i = 0; i < 100 ; i++)
    {
        atomicAdd(&a[i], 1.0f);
    }
}
void cuTestAtomicAdd(float *a)
{
    testAdd<<<1, 10>>>(a);
}

int main(){

  float *d_data, *h_data;
  h_data=(float *) malloc(100*sizeof(float));
  cudaMalloc((void **)&d_data, 100*sizeof(float));
  cudaMemset(d_data, 0, 100*sizeof(float));
  cuTestAtomicAdd(d_data);
  cudaMemcpy(h_data, d_data, 100*sizeof(float), cudaMemcpyDeviceToHost);
  for (int i = 0; i < 100; i++)
    if (h_data[i] != 10.0f) {printf("mismatch at %d, was %f, should be %f\n", i, h_data[i], 10.0f); return 1;}
  printf("Success\n");
  return 0;
}
Другие вопросы по тегам