这节主要涉及到一个多线程情况下存在的数据竞争问题 -- 多个线程同时访问共享数据时,由于没有正确的同步机制,导致数据出现不一致的情况。

  • C/C++ 多线程中,可以通过互斥锁(mutex)、原子操作(atomic,C++11 也提供了原子操作库,如std::atomic,用于实现原子加法、原子赋值等操作)、线程局部变量(C++11提供了thread_local,它为每个线程分配了一份独立的内存,使得不同线程之间的局部变量互不干扰。这样可以避免多个线程访问同一共享数据时的数据竞争问题)以及使用同步代码块(using)、全局变量等措施来避免多线程操作

  • 由于CUDA采用单指令多线程(Single-Instruction Multiple-Thread,SIMT)来管理和执行 GPU 上的众多线程,因此在操作数据时,也会存在数据竞争等问题,而在CUDA中避免数据竞争的方法主要包括使用原子操作适当的索引计算

原子操作可以确保在多线程环境下对共享变量进行原子的读写操作,从而避免数据竞争。

利用线程索引计算可以使得每个线程操作不同的数据元素,避免竞争

上代码:

__global__ void increment_naive(int *g)
{
int idx = threadIdx.x + blockIdx.x * blockDim.x;
idx = idx % ARRAYSIZE;
// g[idx] = g[idx] + 1;
printf("before %d:%d\n", idx, g[idx]);
atomicAdd(& g[idx], 1);
printf("after %d:%d\n", idx, g[idx]);
}

从主机代码中将数据拷贝到设备端,默认都是放在设备的全局内存中(也就是global memory中),在运行核函数时从全局内存中读数据、运算、写入全局内存

  • 首先多个线程会同时从全局内存中取出g[idx]的数据,
  • 运算, g[idx] = g[idx] + 1; 虽然此处计算了,也写入了对应的g[idx]中,但是其他线程并没有拿到这个线程计算的的结果,他们用的数据还是最开始的原始数据,导致最后计算出错

    atomicAdd(& g[idx], 1);该函数为CUDA提供的原子函数接口,该接口详细描述如下:
int atomicAdd(int* address, int val);
unsigned int atomicAdd(unsigned int* address,
unsigned int val);
unsigned long long int atomicAdd(unsigned long long int* address,
unsigned long long int val);
float atomicAdd(float* address, float val);
double atomicAdd(double* address, double val);
__half2 atomicAdd(__half2 *address, __half2 val);
__half atomicAdd(__half *address, __half val);
__nv_bfloat162 atomicAdd(__nv_bfloat162 *address, __nv_bfloat162 val);
__nv_bfloat16 atomicAdd(__nv_bfloat16 *address, __nv_bfloat16 val);

上面是 device-wide atomicAdd 不同数据类型的定义,表示从第一个参数 address 指针指向的内存地址(可以是全局内存或共享内存)中读取16位、32位或64位数据(记做旧值 old),与第二个参数val 做一个加法计算(old + val),然后将求和结果写回到 address 指针指向的内存地址中,并返回未做计算前的旧值 old。这三个操作在一个原子事务中执行。

  • 32位 floating-point 浮点版本的 atomicAdd() 仅由计算能力 2.x 及更高版本的设备支持。
  • 64位 floating-point 浮点版本的 atomicAdd()只被具有计算能力 6.x 及更高版本的设备支持。
  • 32位 __half2 浮点版本的 atomicAdd() 只被具有计算能力 6.x 及更高版本的设备支持。对于两个__half 或__nv_bfloat16 元素,分别保证 __half2 或 __nv_bfloat162 添加操作的原子性;整个__half2 或 __nv_bfloat162 不能保证作为单个32位访问是原子的。
  • 16位 __half 浮点版本的 atomicAdd() 仅由计算能力为 7.x 及更高版本的设备支持。
  • 16位 __nv_bfloat16 浮点版本的 atomicAdd() 仅由计算能力为 8.x 及更高版本的设备支持。

CUDA原子操作的更多相关文章

  1. 5.1 CUDA atomic原子操作

    和许多多线程并行问题一样,CUDA也存在互斥访问的问题,即当一个线程改变变量X,而另外一个线程在读取变量X的值,执行原子操作类似于有一个自旋锁,只有等X的变量在改变完成之后,才能执行读操作,这样可以保 ...

  2. 【CUDA并行程序设计系列(1)】GPU技术简介

    http://www.cnblogs.com/5long/p/cuda-parallel-programming-1.html 本系列目录: [CUDA并行程序设计系列(1)]GPU技术简介 [CUD ...

  3. 《GPU高性能编程CUDA实战》附录一 高级原子操作

    ▶ 本章介绍了手动实现原子操作.重构了第五章向量点积的过程.核心是通过定义结构Lock及其运算,实现锁定,读写,解锁的过程. ● 章节代码 #include <stdio.h> #incl ...

  4. CUDA atomic原子操作

    CUDA的原子操作可以理解为对一个变量进行"读取-修改-写入"这三个操作的一个最小单位的执行过程,这个执行过程不能够再分解为更小的部分,在它执行过程中,不允许其他并行线程对该变量进 ...

  5. CUDA: 原子操作

    1.1以上计算功能集支持全局内存上的原子操作, 1.2以上支持共享内存上的原子操作. atomicAdd(add,y)将生成一个原子的操作序列,这个操作序列包括读取地址addr处的值,将y增加到这个值 ...

  6. CUDA 进阶学习

    CUDA基本概念 CUDA网格限制 1.2CPU和GPU的设计区别 2.1CUDA-Thread 2.2CUDA-Memory(存储)和bank-conflict 2.3CUDA矩阵乘法 3.1 全局 ...

  7. CUDA从入门到精通

    http://blog.csdn.net/augusdi/article/details/12833235 CUDA从入门到精通(零):写在前面 在老板的要求下.本博主从2012年上高性能计算课程開始 ...

  8. 5.2 CUDA Histogram直方图

    什么是Histogramming Histogramming是一种从大的数据集中提取典型特征和模式的方式. 在统计学中,直方图(英语:Histogram)是一种对数据分布情况的图形表示,是一种二维统计 ...

  9. CUDA C Best Practices Guide 在线教程学习笔记 Part 1

    0. APOD过程 ● 评估.分析代码运行时间的组成,对瓶颈进行并行化设计.了解需求和约束条件,确定应用程序的加速性能改善的上限. ● 并行化.根据原来的代码,采用一些手段进行并行化,例如使用现有库, ...

  10. CUDA C

    一.CUDA结构 硬件:GPU(Graphics Processing Unit)   SM(Streaming Multiprocessor)     SP(Streaming Processor) ...

随机推荐

  1. Go实现动态开点线段树

    1.线段树介绍 线段树是一种用于高效处理区间查询和区间更新的数据结构,当我们需要解决一个频繁更新区间值的问题的时候,就可以采用线段树的结构进行解决.线段树的核心思想是将区间分为多个子区间进行管理,越往 ...

  2. Idea - 关于mybatis的插件

      idea中配置的mybatis的mapper类和xml文件的图标怎么自动变为mybatis的logo?需要安装什么插件,怎么安装?   在 IntelliJ IDEA 中,要使 MyBatis 的 ...

  3. 【Python】批量提取Fibersim xml文件中的节点网格数据

    程序功能: 输入需求: fibersim导出的ply 的xml文件,可以很多个也没问题.但名字要有规律,不然没法循环读写.比如我自己用的就是x1.xml.x2.xml.Y1.xml......的文件名 ...

  4. 【ABAQUS模态动力学】Material-Damping 对模态分析的影响

    先说结论,执行Frequency Step (特征值提取)时定义材料行为中的Damping 行为,对结果没有影响. 1. abaqus calculation compare 1.1 ANALYSIS ...

  5. 基于近红外与可见光双目摄像头的人脸识别与活体检测,文末附Demo

    基于近红外与可见光双目摄像头的活体人脸检测原理 人脸活体检测(Face Anti-Spoofing)是人脸识别系统中的重要一环,它负责验证捕捉到的人脸是否为真实活体,以抵御各种伪造攻击,如彩色纸张打印 ...

  6. [tldr] 配置windows terminal使用git bash

    windows terminal默认使用power shell作为shell,但是power shell不好用,还是习惯linux的命令行行为. 参考Windows Terminal 配置 Git B ...

  7. Oracle VM VirtualBox虚拟机安装Centos

    virtualBOx 6.x.x版本跟 virtualBOx 5.x.x 界面已经不一样,但安装步骤还是一样的 镜像下载可以使用下面帖子中的,网易镜像或者阿里云镜像,选取适合自己的镜像 开源镜像站,v ...

  8. OpenGL ES与GLSL ES各版本对应说明

    OpenGL ES 3.2 OpenGL ES 3.2 and OpenGL ES Shading Language 3.20 OpenGL ES 3.1 OpenGL ES 3.1 and Open ...

  9. apisix~hmac-auth插件的使用

    hmac-auth插件需要和 Consumer 一起使用,API 的使用者必须将密匙添加到请求头中以验证其请求,下面介绍它的主要用法 参数 algorithm 算法 默认hmac-sha256 [&q ...

  10. Win10禁用UWP

    Win10禁用UWP, HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsStore DisableStoreApps REG_DWORD 0 ...