@@ -355,3 +355,97 @@ int main() {
355
355
host_lambda(1);
356
356
}
357
357
` ` `
358
+
359
+ # ## 第一个 CUDA 程序
360
+
361
+ ` ` ` cuda
362
+ #include <cuda_runtime.h>
363
+ #include <nvfunctional>
364
+ #include "cudapp.cuh" // 小彭老师现代 CUDA 框架,更符合现代 C++ 风格,减少官方 C 风格接口的繁琐
365
+
366
+ using namespace cudapp;
367
+
368
+ __global__ void kernel(int x) {
369
+ printf("线程编号 (%d, %d)\n ", blockIdx.x, threadIdx.x);
370
+ }
371
+
372
+ int main() {
373
+ // 三箭头语法糖启动内核
374
+ // kernel<<<blockDim, gridDim>>>(...)
375
+ kernel<<<3, 4>>>();
376
+
377
+ // 强制同步:等待此前启动过的所有内核执行完成
378
+ cudaDeviceSynchronize();
379
+
380
+ return 0;
381
+ }
382
+ ` ` `
383
+
384
+ 重要知识点:CUDA 为了极致性能,会使用**异步**的方式启动内核。
385
+
386
+ 使用三箭头语法调用内核函数,只是把内核提交到 GPU 上去而已,不代表内核已经在 GPU 上执行完毕。
387
+
388
+ 而 `cudaDeviceSynchronize()` 的作用就是等待**此前提交的所有内核**执行完毕,然后才能继续往下执行 `return 0`。
389
+
390
+ > {{ icon.warn }} 如果不在程序退出前强制同步,则内核可能未执行!printf 语句会不生效!
391
+
392
+ # ## 类比
393
+
394
+ 为了方便理解,可以把 `kernel<<<3, 4>>>()` 看作是启动了一个**后台线程**,而且还是以 `detach` 的方式,启动后就在后台默默运行,不会阻塞启动了内核的 CPU 线程。
395
+
396
+ | GPU 操作 | CPU 类比 |
397
+ |-|-|
398
+ | 启动内核 `kernel<<<3, 4>>>()` | `std::async` 或 `std::thread` |
399
+ | `cudaDeviceSynchronize` | `future.wait()` 或 `thread.join()` |
400
+
401
+ # ## 小彭老师为你准备的 CUDA 框架
402
+
403
+ ` ` ` cuda
404
+ #include <cuda_runtime.h>
405
+ #include <nvfunctional>
406
+ #include "cudapp.cuh" // 小彭老师现代 CUDA 框架,更符合现代 C++ 风格,减少官方 C 风格接口的繁琐
407
+
408
+ using namespace cudapp;
409
+
410
+ __global__ void kernel(int x) {
411
+ printf("内核参数 x = %d\n ", x);
412
+ printf("线程编号 (%d, %d)\n ", blockIdx.x, threadIdx.x);
413
+ }
414
+
415
+ int main() {
416
+ // 启动内核的3种方式
417
+ // 1. 官方三箭头语法糖(常用)
418
+ // kernel<<<blockDim, gridDim, dynamicSmemBytes, stream>>>(...)
419
+ int x = 42;
420
+ kernel<<<3, 4, 0, 0>>>(x);
421
+
422
+ // 2. cudaLaunchKernel
423
+ void *args[] = {&x};
424
+ CHECK_CUDA(cudaLaunchKernel(kernel, dim3(3), dim3(4), args, 0, 0));
425
+
426
+ // 3. cudaLaunchKernelEx
427
+ cudaLaunchConfig_t cfg{};
428
+ cfg.blockDim = dim3(3);
429
+ cfg.gridDim = dim3(4);
430
+ cfg.dynamicSmemBytes = 0;
431
+ cfg.stream = 0;
432
+ cfg.attrs = nullptr;
433
+ cfg.numAttrs = 0;
434
+ CHECK_CUDA(cudaLaunchKernelEx(&cfg, kernel, x));
435
+
436
+ const char *name;
437
+ CHECK_CUDA(cudaFuncGetName(&name, kernel));
438
+ printf("内核名字:%s\n ", name);
439
+
440
+ // 1. 强制同步:等待此前启动过的所有内核执行完成
441
+ CHECK_CUDA(cudaDeviceSynchronize());
442
+
443
+ // 2. 仅同步 0 号流(null-stream)
444
+ CHECK_CUDA(cudaStreamSynchronize(0));
445
+
446
+ // 3. 仅同步 0 号流,但使用小彭老师现代 CUDA 框架
447
+ CudaStream::nullStream().join();
448
+
449
+ return 0;
450
+ }
451
+ ` ` `
0 commit comments