- 博客(49)
- 收藏
- 关注
原创 C++并发编程实战 #2 在线程间共享数据
在C++中,通过构造mutex的实例来创建互斥,调用成员函数lock()对其进行加锁,调用unlock()进行解锁。不推荐直接使用成员函数进行加锁和解锁,因为若按此处理,则在函数的每条代码路径上都要调用unlock(),包括由于异常导致退出的路径。因此,使用lock_guard<>来进行加锁和解锁。其在构造时给互斥加锁,在析构时解锁,从而保证互斥总被正确解锁。
2024-06-10 10:18:02
274
原创 C++并发编程实战 #1 线程管控
如果给定一个线程,只要令thread对象与之关联,就能管控该线程的几乎每个细节。每个C++程序都至少有一个线程,即运行main()的线程,它由C++运行时系统启动。随后,可以发起更多线程,以别的函数作为入口。main()函数返回时,程序就会推出;同样,当入口函数返回时,对应线程随之结束。
2024-05-21 21:11:33
993
原创 CUDA调整指令级原语
在GPU上运行的运算密集型应用程序,处理器的计算吞吐量可以用它在一段时间内执行操作的数量来衡量。因为GPU有很多SIMT指令和计算核心,所以其峰值计算吞吐量通常比其他的处理器高。对应用程序的吞吐量和正确性进行优化时,理解不同低级原语的性能、数值精确度和线程安全性方面的优缺点很重要。
2024-05-06 13:23:50
952
原创 CUDA常量内存
常量内存是一种专用内存,用于只读数据和统一访问线程束中线程的数据。常量内存对于内核代码是只读的,但对主机而言是可读写的。常量内存位于设备的DRAM上,并且有一个专用的片上缓存。从每个SM的常量缓存中读取的延迟,比直接从常量内存中读取的低得多。常量内存有一个不同于其他内存的最优访问模式。在常量内存中,如果线程束中的所有线程都访问相同的位置,那么这个访问模式就是最优的。如果线程束中的线程访问不同的地址,则访问就需要串行。因此,一个常量内存读取的成本与线程束中线程读取唯一地址的数量呈线性关系。
2024-05-04 14:06:25
1055
原创 CUDA内存访问模式
大多数设备端数据访问都是从全局内存开始的,并且多数GPU应用程序容易受内存带宽的限制。因此,最大限度的利用全局内存带宽是调控核函数性能的基本。
2024-05-02 21:20:50
1251
原创 CUDA内存管理
随着CUDA版本的升级,NVIDIA可以实现主机和设备内存空间的统一,但对大多数应用程序来说,仍然需要手动移动数据。重点在于如何使用CUDA函数来显式地管理内存和数据移动。
2024-05-02 14:46:43
786
原创 CUDA内存模型
GPU和CPU内存模型的主要区别是,CUDA编程模型能将内存层次结构更好地呈现给用户,能让我们显示的控制它的行为。可编程的:需要显示的控制哪些数据存放在可编程内存中不可编程的:不能决定数据的存放位置,程序自动生成存放位置寄存器共享内存本地内存常量内存纹理内存全局内存图中所示为这些内存空间的层次结构,每个都有不同的作用域、生命周期和缓存行为。一个核函数中的线程都有自己私有的本地内存。一个线程块有自己的共享内存,对同一线程块内的所有线程可见,其内容持续线程块的整个生命周期。
2024-05-01 22:37:04
993
原创 CUDA执行模型2
由SM处理的每个线程束的执行上下文,在整个线程束的生存期中是保存在芯片内的。每个SM都有32位的寄存器组,存储在寄存器文件中,在线程中进行分配。SM(Streaming Multiprocessor,流多处理器)寄存器是指用于存储线程的状态和临时数据的存储器单元。每个线程在执行时都会被分配一定数量的寄存器,用于存储其局部变量、中间计算结果等。这些寄存器是线程私有的,不同线程之间不能直接访问对方的寄存器。:每个线程在执行时需要保存一些状态信息,如程序计数器、栈指针等,这些状态信息存储在寄存器中。
2024-04-28 20:22:00
634
原创 CUDA执行模型
GPU的架构是围绕一个流式多处理器(SM)的可扩展阵列搭建的。可以通过复制这种架构的构建块来实现GPU的硬件并行。SM是GPU中的一个重要组件,负责执行CUDA核函数中的线程块(Thread Block)。每个SM包含多个CUDA核心,可以同时执行多个线程块中的线程,以实现并行计算。每个CUDA核心有自己的缓存器,也可以访问同一个SM中的共享内存。每个CUDA核心可以并行多个线程。简单来说,一个GPU可以并行的最大线程数=CUDA核心数*一个CUDA核心可以并行的线程数。
2024-04-28 14:23:31
1332
1
原创 CUDA核函数
一个CUDA函数的调用<<<>>>中间的部分,是核函数的运行配置。执行配置的第一个值是网格维度,也就是启动块的数目;第二个值是块维度,也就是每个块中线程的数目。由于数据在全局内存中是线性存储的,因此可以用变量blockIdx.x和threadIdx.x来进行以下操作。核函数的调用与主机线程是异步的。核函数调用结束后,控制权立刻返回给主机端。举个栗子我们在调用核函数之后,控制权立刻返回给主机端,所以先打印了hello cpu,然后才打印了GPU的核函数的输出。
2024-04-25 13:23:46
908
1
原创 CUDA线程管理
核函数在主机端启动时,执行会转移到设备上,并且将。当核函数在GPU上运行时,主机可以运行其他函数。因此,。此时,设备端也就是GPU上会产生大量的线程,并且每个线程都执行由核函数指定的语句。
2024-04-23 22:53:45
980
原创 Effective C++——在使用前初始化对象
在构造函数中为每个成员变量赋值的方式,并不是对象的初始化过程,成员变量的初始化在比调用构造函数更早之前进行。而初始值列表的方式才是对对象的初始化。如果,A中的成员变量有其他类的对象,那么在第一种方式中,会调用其默认构造函数后,再对其进行赋值。而初始值列表的方式,直接由A的实参拿来调用其成员变量对象的复制构造函数。这会提高效率,但是如果成员变量都是内置类型,效率不会提高太多。
2024-01-19 16:43:04
425
原创 Effective C++——尽可能使用const
const是个威力强大的助手。尽可能使用它。你会为你的作为感到高兴。——《Effective C++》
2024-01-17 21:04:58
1085
原创 C++对象在内存中有多大
当调用一个对象的虚函数时,实际上是通过该对象的虚函数指针查找虚函数表,并从表中找到相应的函数地址进行调用。对于包含虚函数的类,编译器会在对象的内存布局中添加一个指向虚函数表的指针,称为虚函数指针或 vptr。虚函数表是一个表格,其中包含了类的虚函数的地址。不会改变这个student类对象在内存中的大小,因为新增的虚函数是在虚函数表中添加的,而对象中保存的依旧只有一个指向虚函数表的指针。上面这个student类,包含一个int型的age变量,一个char类型的指针,还有一个指向虚函数表的指针。
2023-12-14 13:14:23
58
原创 C++设计模式#1
将MainForm这个高层模块与不稳定的Line,Rect等容易变化的类剥离开,将其抽象成shape类,从而摆脱高层模块对不稳定的底层模块的依赖。通用性的技术,由于不能掌握全部的复杂对象,我们选择忽略其非本质细节,而处理泛化和理想化的对象模型。分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单问题。
2023-12-08 17:35:47
141
原创 C++中的命名空间
class A {};...定义了一个名为cplusplus_primer的命名空间。命名空间可以定义在全局作用域内,也可以定义在其他命名空间中。但是,不能定义在函数或类的内部。命名空间作用域后面无须分号。
2023-11-14 21:59:33
69
原创 C++中#include““和<>的区别
include关键字用来标识编译中引用的头文件,编译器会自动去查找这些头文件中的变量、函数声明、结构体定义等相关信息。""和的区别在于查找文件的路径不同,优先在编译器或IDE预先指定的搜索目录中进行搜索,通常会搜索目录。""优先在当前目录下进行搜索,如果没有再到指定路径下进行搜索,(编译时以-I指定的目录),最后到路径下搜索。通常,引用标准库头函数时使用,引用自己定义的头文件使用""
2023-11-06 22:20:16
354
原创 CUDA编程模型#2
在CUDA程序中,有两组不同的网格和块变量:手动定义的dim3数据类型和预定义的uint3数据类型。当执行核函数时,CUDA运行时会生成相应的内置预初始化的网格、块和线程变量,它们在核函数内均可被访问到且为uint3类型。同一网格中的所有线程共享相同的全局内存空间。一个网格由多个线程块构成,一个线程块包含一组线程,同一线程块内的线程协作可以通过以下方式来实现。该坐标变量是基于uint3定义的cuda内置的向量类型,是一个包含3个无符号整数的结构,可以通过x,y,z三个字段来指定。不同块内的线程不能协作。
2023-09-27 21:40:02
92
原创 CUDA编程模型
CUDA提出了一个线程层次结构抽象的概念,以允许控制线程行为。在硬件层,理解线程是如何映射到核心可以帮助提高其性能。内核(kernel)是CUDA编程模型的一个重要组成部分,其代码在GPU上运行。在GPU上编写核函数,在主机端,基于应用程序数据及GPU性能定义如何让设备实现算法功能。多数情况下,主机可以独立地对设备进行操作。内核一旦被启动,管理权立刻返回给主机,释放CPU来执行由设备上运行的并行代码实现的额外任务。
2023-09-21 21:39:53
104
原创 C++中判断输入路径是文件夹还是具体文件(windows&linux)
记录一个需求:在一个C++项目中,如果输入的路径是一个文件夹,那么把当前路径中的所有文件进行处理,如果是一个具体的文件,就直接处理一个文件。因为需要可移植,现在只完成了如何在windows上完成,后面再写如何在Linux上完成。
2023-09-21 17:14:51
927
原创 基于CUDA的异构并行计算
基于《CUDA C编程 权威指南》在并行算法的实现中,分析数据的相关性是最基本的内容,因为相关性是限制并行计算的一个主要因素。在大多数情况下,具有依赖性的任务之间的独立的关系链为并行化提供了和好的机会。
2023-09-20 22:24:27
166
1
原创 C++ CUDA编程#2
核函数可以调用不带执行配置的自定义函数,即设备函数。设备函数在设备中执行、在设备中被调用;而核函数在设备中执行、在主机中被调用。__global__修饰的函数称为核函数,一般由主机调用、在设备中执行;__device__修饰的函数称为设备函数,只能被核函数或其他设备函数调用、在设备中执行;__host__修饰主机段的普通 c++ 函数,在主机中被调用、在主机中执行,一般可以省略;可以同时用__host__和__device__修饰函数,从而减少代码冗余,此时编译器将 分别在主机和设备上编译该函数。
2023-08-31 17:20:18
138
原创 C++#pragma
pragma是一个预处理器指令,用于向编译器传递特定的编译指示。不同的编译器对于“#pragma"的支持和行为会有所不同。因此pragma不是C++标准的一部分,而是编译器提供的一种扩展。通过使用#pragma,可以向编译器发出一些命令,影响代码的编译、链接或优化。下面是一些常见的#pragma用法。
2023-08-31 16:06:37
692
原创 C++ CUDA编程#1
基于《cuda编程-基础与实践》CUDA 提供两层 API,即 CUDA 驱动API 和 CUDA 运行时API。CUDA 开发环境中,程序应用程序是以主机(CPU)为出发点的;应用程序可以调用 CUDA 运行时 API、CUDA 驱动 API 和一些已有的 CUDA 库。CUDA 采用 nvcc 作为编译器,支持 C++ 代码;nvcc 在编译 CUDA 程序时,会将纯粹的 c++ 代码交给 c++ 编译器,自己负责编译剩下的 cu 代码。CUDA程序的后缀是.cu而不是.cpp。
2023-08-30 16:41:20
332
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人