@@ -355,3 +355,97 @@ int main() {
355355 host_lambda(1);
356356}
357357` ` `
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