我建議你花一些精力來編譯和運行你的代碼,並進行適當的cuda錯誤檢查。學習解釋編譯器輸出和運行時輸出將使您成爲更好,更智能,更高效的編碼器。我還建議查看我以前在here指出的那篇文章。它處理這個確切的主題,幷包括鏈接的工作示例。這個問題是一個重複的問題。
有各種錯誤:
StructA *d_A = (StructA*)malloc(numS * sizeof(StructA));
上面的代碼行創建在宿主存儲器大小StructA
的結構的分配,並且將指針d_A
指向該分配的開始。目前沒有錯。
cudaMalloc((void**)&(d_A), numS * sizeof(StructA));
上面的代碼行中設備創建的分配存儲器的StructA
大小,並且將指針d_A
指向該分配的開始。這有效地消除了以前的指針和分配。 (之前的主機分配仍然存在,但你無法訪問它,它基本上已經丟失。)當然,這不是你的意圖。
int *h_A = d_a->a;
現在d_A
(我假設你的意思d_A
,不d_a
)已經被指定爲設備內存指針,->
操作將取消引用該指針定位元素a
。這是主機代碼中的非法,並將引發錯誤(seg故障)。
cudaMalloc(&(d_A->a), row*col*sizeof(int));
這行代碼有類似的問題。我們不能cudaMalloc
住在設備內存中的指針。 cudaMalloc
創建生活在主機內存中的指針,但引用設備內存中的位置。此操作&(d_A->a)
正在取消引用主機代碼中非法的設備指針。
正確的代碼會是這樣的:
$ cat t363.cu
#include <stdio.h>
typedef struct {
int *a;
int foo;
} StructA;
__global__ void kernel(StructA *data){
printf("The value is %d\n", *(data->a + 2));
}
int main()
{
int numS = 1; // defined at runtime
//allocate host memory for the structure storage
StructA *h_A = (StructA*)malloc(numS * sizeof(StructA));
//allocate host memory for the storage pointed to by the embedded pointer
h_A->a = (int *)malloc(10*sizeof(int));
// initialize data pointed to by the embedded pointer
for (int i = 0; i <10; i++) *(h_A->a+i) = i;
StructA *d_A; // pointer for device structure storage
//allocate device memory for the structure storage
cudaMalloc((void**)&(d_A), numS * sizeof(StructA));
// create a pointer for cudaMalloc to use for embedded pointer device storage
int *temp;
//allocate device storage for the embedded pointer storage
cudaMalloc((void **)&temp, 10*sizeof(int));
//copy this newly created *pointer* to it's proper location in the device copy of the structure
cudaMemcpy(&(d_A->a), &temp, sizeof(int *), cudaMemcpyHostToDevice);
//copy the data pointed to by the embedded pointer from the host to the device
cudaMemcpy(temp, h_A->a, 10*sizeof(int), cudaMemcpyHostToDevice);
kernel<<<1, 1>>>(d_A); // Passing pointer to StructA in device
cudaDeviceSynchronize();
}
$ nvcc -arch=sm_20 -o t363 t363.cu
$ cuda-memcheck ./t363
========= CUDA-MEMCHECK
The value is 2
========= ERROR SUMMARY: 0 errors
$
你會注意到,我還沒有制定出來,你所面對的是StructA
(即numS
> 1)的陣列的情況下,將需要一個循環。我會留給你看看我在這裏和我的previous linked answer中提出的邏輯,看看你是否可以計算出這個循環的細節。此外,爲了簡潔起見,我省去了通常的cuda error checking,但請在您的代碼中使用它。最後,如果你還沒有得出結論,這個過程(有時稱爲「深層複製操作」)在普通CUDA中有點繁瑣。沿着這些方向的先前建議是「扁平化」這種結構(以便它們不會控制指針),但是您也可以探索cudaMallocManaged
,即Unified Memory in CUDA 6。
謝謝!這是關於'cudaMalloc'的最終解釋。我非常感謝你提供答案的時間。 'malloc'與下一個'cudaMalloc'所造成的分配是我以前沒有想到或知道的。 – mrei
我正在玩你的示例代碼。由於我處於計算能力1.3環境,並且無法從設備打印,因此我試圖將修改的(例如'data-> a [2] = 5;')結構進行復制。但是,我無法複製回來(我認爲它會是:'cudaMemcpy(h_A,d_A,10 * sizeof(StructA),cudaMemcpyDeviceToHost);') – mrei
這可能會複製結構,但它會不要複製由嵌入式指針指向的數據。如果您查看將該數據複製到設備的代碼行,您應該能夠將其反轉爲從設備中檢索該數據。如果你想取得進展,你需要對C結構,指針和動態分配有一個合理的理解。複製指針(這是結構中的內容)不會*複製指針指向的數據。 –