위의 두 번째 주석에서 언급했듯이 두 개의 32 비트 수량을 하나의 64 비트 원자 적 관리 수량으로 결합하여 문제를 해결할 수 있습니다. 그런 다음 arbitrary atomic example을 대략적인 가이드로 사용하여 원자 적으로 64 비트 양을 관리합니다. 분명히이 아이디어를 두 개의 32 비트 수량 이상으로 확장 할 수는 없습니다.
#include <stdio.h>
#define DSIZE 5000
#define nTPB 256
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
exit(1); \
} \
} while (0)
typedef union {
float floats[2]; // floats[0] = lowest
int ints[2]; // ints[1] = lowIdx
unsigned long long int ulong; // for atomic update
} my_atomics;
__device__ my_atomics test;
__device__ unsigned long long int my_atomicMin(unsigned long long int* address, float val1, int val2)
{
my_atomics loc, loctest;
loc.floats[0] = val1;
loc.ints[1] = val2;
loctest.ulong = *address;
while (loctest.floats[0] > val1)
loctest.ulong = atomicCAS(address, loctest.ulong, loc.ulong);
return loctest.ulong;
}
__global__ void min_test(const float* data)
{
int idx = (blockDim.x * blockIdx.x) + threadIdx.x;
if (idx < DSIZE)
my_atomicMin(&(test.ulong), data[idx],idx);
}
int main() {
float *d_data, *h_data;
my_atomics my_init;
my_init.floats[0] = 10.0f;
my_init.ints[1] = DSIZE;
h_data = (float *)malloc(DSIZE * sizeof(float));
if (h_data == 0) {printf("malloc fail\n"); return 1;}
cudaMalloc((void **)&d_data, DSIZE * sizeof(float));
cudaCheckErrors("cm1 fail");
// create random floats between 0 and 1
for (int i = 0; i < DSIZE; i++) h_data[i] = rand()/(float)RAND_MAX;
cudaMemcpy(d_data, h_data, DSIZE*sizeof(float), cudaMemcpyHostToDevice);
cudaCheckErrors("cmcp1 fail");
cudaMemcpyToSymbol(test, &(my_init.ulong), sizeof(unsigned long long int));
cudaCheckErrors("cmcp2 fail");
min_test<<<(DSIZE+nTPB-1)/nTPB, nTPB>>>(d_data);
cudaDeviceSynchronize();
cudaCheckErrors("kernel fail");
cudaMemcpyFromSymbol(&(my_init.ulong), test, sizeof(unsigned long long int));
cudaCheckErrors("cmcp3 fail");
printf("device min result = %f\n", my_init.floats[0]);
printf("device idx result = %d\n", my_init.ints[1]);
float host_val = 10.0f;
int host_idx = DSIZE;
for (int i=0; i<DSIZE; i++)
if (h_data[i] < host_val){
host_val = h_data[i];
host_idx = i;
}
printf("host min result = %f\n", host_val);
printf("host idx result = %d\n", host_idx);
return 0;
}
나는 방법 (PTX하거나 생각하지 않습니다) 특정 GPU 하드웨어를 사용하여 한 번에 두 개 이상의 위치를 원자 적으로 업데이트합니다. 누군가 다른 사람이 영리한 아이디어를 가지고있을 수 있습니다. 일반적으로이 유형의 문제는 "중요 섹션"방법론을 사용하여 해결할 수 있다고 생각합니다. 오른쪽 상단 모서리에있는 검색 상자를 사용하여 "cuda critical section"을 검색하고 그 중 일부 질문에 설명되어있는 내용을 확인하십시오. . 이 작업은 스레드 단위로 실행하는 것이 좋으며 스레드 별 중요 섹션 관리는 매우 위험 할 수 있습니다. –
실제로, 당신이 관리하려고하는 두 개의 32 비트 수량 만있는이 제한된 경우에, 64 비트 양을 활용하여 (아마도 atomicCAS를 중심으로 구축 된) 맞춤 원자 함수를 만들 수 있습니다. (임의의 원자 적 예제) (http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#atomic-functions)에 대한 줄을 따라, 문서에 나와 있습니다. –