Как будто вы пытаетесь получить доступ к объекту, который является null
. Рассмотрим ниже пример:
TypeA objA;
. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException
, что имеет смысл.
См. Также этот пример:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Что-то вроде этого должно, вероятно, работать.
#include <algorithm>
#define NDEBUG
#define CUT_CHECK_ERROR(errorMessage) do { \
cudaThreadSynchronize(); \
cudaError_t err = cudaGetLastError(); \
if( cudaSuccess != err) { \
fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n", \
errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
exit(EXIT_FAILURE); \
} } while (0)
__device__ float *devPtr;
__global__
void kernel1(float *some_neat_data)
{
devPtr = some_neat_data;
}
__global__
void kernel2(void)
{
devPtr[threadIdx.x] *= .3f;
}
int main(int argc, char *argv[])
{
float* otherDevPtr;
cudaMalloc((void**)&otherDevPtr, 256 * sizeof(*otherDevPtr));
cudaMemset(otherDevPtr, 0, 256 * sizeof(*otherDevPtr));
kernel1<<<1,128>>>(otherDevPtr);
CUT_CHECK_ERROR("kernel1");
kernel2<<<1,128>>>();
CUT_CHECK_ERROR("kernel2");
return 0;
}
Дайте ему водоворот.
Проведите некоторое время, фокусируясь на обильной документации, предлагаемой NVIDIA.
Из руководства по программированию:
float* devPtr;
cudaMalloc((void**)&devPtr, 256 * sizeof(*devPtr));
cudaMemset(devPtr, 0, 256 * sizeof(*devPtr));
Это - простой пример того, как выделить память. Теперь, в Ваших ядрах, необходимо принять указатель на плавание как так:
__global__
void kernel1(float *some_neat_data)
{
some_neat_data[threadIdx.x]++;
}
__global__
void kernel2(float *potentially_that_same_neat_data)
{
potentially_that_same_neat_data[threadIdx.x] *= 0.3f;
}
Таким образом, теперь можно вызвать их как так:
float* devPtr;
cudaMalloc((void**)&devPtr, 256 * sizeof(*devPtr));
cudaMemset(devPtr, 0, 256 * sizeof(*devPtr));
kernel1<<<1,128>>>(devPtr);
kernel2<<<1,128>>>(devPtr);
Поскольку эти данные используются в многочисленных функциях, я хотел бы, чтобы они были глобальны.
Существует немного серьезных оснований использовать globals. Это определенно не то. Я оставлю его как осуществление для расширения этого примера для включения перемещения "devPtr" в глобальную область видимости.
Править:
Хорошо, фундаментальная проблема - это: Ваши ядра могут только память устройства доступа и единственные указатели глобальной области видимости, которые они могут использовать, GPU. Когда вызов ядра от Вашего ЦП, негласно что происходит, состоит в том, что указатели и примитивы копируются в регистры GPU и/или общую память, прежде чем ядро будет выполнено.
Таким образом, самое близкое, которое я могу предложить, является этим: используйте cudaMemcpyToSymbol () для достижения целей. Но в фоновом режиме полагайте, что другой подход мог бы быть Правильной Вещью.
#include <algorithm>
__constant__ float devPtr[1024];
__global__
void kernel1(float *some_neat_data)
{
some_neat_data[threadIdx.x] = devPtr[0] * devPtr[1];
}
__global__
void kernel2(float *potentially_that_same_neat_data)
{
potentially_that_same_neat_data[threadIdx.x] *= devPtr[2];
}
int main(int argc, char *argv[])
{
float some_data[256];
for (int i = 0; i < sizeof(some_data) / sizeof(some_data[0]); i++)
{
some_data[i] = i * 2;
}
cudaMemcpyToSymbol(devPtr, some_data, std::min(sizeof(some_data), sizeof(devPtr) ));
float* otherDevPtr;
cudaMalloc((void**)&otherDevPtr, 256 * sizeof(*otherDevPtr));
cudaMemset(otherDevPtr, 0, 256 * sizeof(*otherDevPtr));
kernel1<<<1,128>>>(otherDevPtr);
kernel2<<<1,128>>>(otherDevPtr);
return 0;
}
Не забывайте '-host-compilation=c ++' для этого примера.
Я шел вперед и попробовал решение выделения временного указателя и передачи его к простой глобальной функции, подобной kernel1.
Хорошие новости - то, что это действительно работает :)
Однако я думаю, что это путает компилятор, поскольку я теперь получаю "Консультацию: не Может сказать то, на что указывает указатель, принимая пространство глобальной памяти" каждый раз, когда я пытаюсь получить доступ к глобальным данным. К счастью предположение, оказывается, корректно, но предупреждения являются раздражающими.
Так или иначе для записи - я посмотрел на многие примеры и действительно пробегал упражнения Nvidia, где точка должна заставить вывод говорить "Корректный!". Однако я не посмотрел на всех них. Если кто-либо знает о sdk примере, где они делают динамическое выделение памяти глобального устройства, я все еще хотел бы знать.
Erm, это было точно, что проблема перемещения devPtr к глобальной области видимости, которая была моей проблемой.
У меня есть реализация, которая делает точно, что, с этими двумя ядрами, имеющими указатель на данные, передал в. Я явно не хочу передавать в тех указателях.
Я прочитал документацию справедливо тесно и подбросил форумы Nvidia ударом (и Google, искавший в течение приблизительно одного часа), но я не нашел реализацию глобального динамического массива устройства, который на самом деле работает (я попробовал несколько что компиляция и затем перестал работать новыми и интересными способами).
проверьте образцы, включенные с SDK. Многие из тех демонстрационных проектов являются достойным способом учиться примером.
Поскольку эти данные используются во многих функциях, я хотел бы, чтобы они были глобальными.
-
Есть несколько веских причин использовать глобальные переменные. Это точно не тот. Я оставлю это как упражнение, чтобы расширить этот пример, включив перемещение «devPtr» в глобальную область.
Что, если ядро оперирует большой константной структурой, состоящей из массивов? Использование так называемой постоянной памяти не вариант, потому что она очень ограничена по размеру ... так что вы должны поместить ее в глобальную память?