CUDA中__syncthreads()和__threadfence_block()和__trheadfence()

2023-11-13

        作为cuda小白,我看完书上对这三个函数的解释,仍然不懂,于是做了以下几个实验来理解这三个函数的使用区别。

        我们先来看看__threadfence_block()是在干啥,这个实验非常简单,A数组的长度为1024(一个block的大小),先往A[0:512]里面写2,再往A[512:1024]里面写1,最后按照倒序把A数组复制到B数组里面,简单预测一下B里面正确的结果应该是11111...22222,即前512个元素全是1,后512个元素全是2。

#include<cuda_runtime.h>
#include<iostream>

template<typename scalar_t>
__global__ void swap(scalar_t* A, scalar_t* B)
{
	unsigned int idx = threadIdx.x + blockDim.x * blockIdx.x;

	// 往A的前512个元素写2,后512个元素写1,然后再把A的所有元素倒着写到B内
	if (idx < 512)
		A[idx] = 2;
	else
		A[idx] = 1;
	//__threadfence_block();	// warp内写完了再往下走
	//__threadfence();		// block内写完了再往下走
	//__syncthreads();		// block内执行到这里再往下走
	B[idx] = A[1023 - idx];		// 正确的B结果应该是111....222
}

int main()
{
	unsigned int len = 1024;
	unsigned int size = len * sizeof(int);
	int* A = new int[len];

	int* A_cuda, * B_cuda;
	cudaMalloc((void**)&A_cuda, size);
	cudaMalloc((void**)&B_cuda, size);
	cudaMemset(A_cuda, 0, size);
	cudaMemset(B_cuda, 0, size);

	swap<<<1, 1024>>>(A_cuda, B_cuda);

	int* B = new int[len];
	cudaMemcpy(B, B_cuda, size, cudaMemcpyDeviceToHost);
	cudaFree(A_cuda);
	cudaFree(B_cuda);

	for (int i = 0; i < len; ++i)
		printf("%d, ", B[i]);
	return 0;
}

不同步的情况下,即不使用代码中14,15,16行的三种同步指令,结果如图,得到了错误的结果,这很容易理解,因为不同warp间执行的顺序并没有做同步,所以A的写操作还没有完成,B就对A进行了复制,所以得到了很多0元素。我还仔细数了一下,相邻的一组0元素正好是32个,等于warp_size。

 使用__threadfence_block之后,结果如图,仍然得到了错误的结果,和不使用__threadfence_block效果差不多,我猜测__threadfence_block的功能是阻塞warp的内存延迟隐藏使之重新暴露,并没有同步不同的warp,书上也说它不会同步任何线程,所以和没使用的效果差不多。

使用__syncthreads之后,结果如图,终于得到了正确的结果,这很容易理解,它同步了一个block内的线程,所以B的复制操作在所有的A写操作之后。

 使用__threadfence之后,结果如图,结果也是正确的,因为__threadfence阻塞了所有块的线程, 所有块都


我们终于弄清楚__threadfence_block和其他两个函数的差别了,但是__syncthreads和__threadfence的差距似乎还没看出来,简单改动代码之后(如下),我把原来一个block拆分为了两个block,并且写了一个循环来拖慢block2的速度(这个循环不会影响正确结果),核函数的任务仍然不变。

#include<cuda_runtime.h>
#include<iostream>

template<typename scalar_t>
__global__ void swap(scalar_t* A, scalar_t* B)
{
	unsigned int idx = threadIdx.x + blockDim.x * blockIdx.x;

	// 拖慢block2的速度
	if (blockIdx.x == 1)
		for (int i = 0; i < 1024; ++i)
			A[idx] = -1;
	
	// 往A的前512个元素写2,后512个元素写1,然后再把A的所有元素倒着写到B内
	if (idx < 512)
		A[idx] = 2;
	else
		A[idx] = 1;
	//__threadfence_block();	// warp内写完了再往下走
	//__threadfence();		// block内写完了再往下走
	//__syncthreads();		// block内执行到这里再往下走
	B[idx] = A[1023 - idx];		// 正确的B结果应该是111....222
}

int main()
{
	unsigned int len = 1024;
	unsigned int size = len * sizeof(int);
	int* A = new int[len];

	int* A_cuda, * B_cuda;
	cudaMalloc((void**)&A_cuda, size);
	cudaMalloc((void**)&B_cuda, size);
	cudaMemset(A_cuda, 0, size);
	cudaMemset(B_cuda, 0, size);

	swap<<<2, 512>>>(A_cuda, B_cuda);

	int* B = new int[len];
	cudaMemcpy(B, B_cuda, size, cudaMemcpyDeviceToHost);
	cudaFree(A_cuda);
	cudaFree(B_cuda);

	for (int i = 0; i < len; ++i)
		printf("%d, ", B[i]);
	return 0;
}

用__syncthreads函数的结果如图,结果是错误的,因为__syncthreads只能同步块内线程,而B的复制是块间进行的,所以结果是错的。

 用__threadfence函数的结果如图,结果是正确的,因为__threadfence能够同步不同块之间的线程,B的复制操作在所有块都完成了A的写操作之后。


至此我们就理清了这三个函数的区别和作用了:

        1.__threadfence_block是阻塞warp直至warp发出的写操作完成,但由于warp本身就是单指令多线程,这个操作就比较多余,一般没什么用。但在分支语句中不能使用__syncthreads时就能派上用场了。

        2.__syncthreads是阻塞block直至block内的线程全都执行到这一行,但不能对块间进行同步。

        3.__threadfence是阻塞grid直至grid内的线程发出的读写操作完成,可以实现块间同步。

PS: 以上均是我的个人理解,如有错误,感谢指出

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CUDA中__syncthreads()和__threadfence_block()和__trheadfence() 的相关文章

  • 无法使用 rtools40 和 R 4.0 构建 RDCOMClient

    不久前 我创建了 RDCOMClient 包的一个分支 以使其与 R 3 6 一起工作 https github com dkyleward RDCOMClient https github com dkyleward RDCOMClien
  • 自动映射器多对一映射

    我想将一种类型映射到另一种类型 但我在第一种类型中有多个属性 需要获取其他类型的一个属性 例如 public class A public int a get set public int b get set public int c ge
  • 如何引用 .net 可执行文件中的类?

    IL 反汇编程序显示了我想在项目中使用的 Net 可执行文件中的类 我如何使用我自己项目中的这些类 从 Visual Studio 上的项目添加对该可执行文件的引用 您应该有权访问它定义的公共类 可执行文件是一个像任何其他程序集一样的程序集
  • Windows 窗体中的切换开关控件

    我正在设计一个拨动开关控制使用CheckBox 但目前我的控件只能画一个圆圈 如何绘制如下图所示的圆形形状 以及如何根据控件的值更改圆圈的位置以表示选中和未选中的状态 如下图所示 这是我的代码 public class MyCheckBox
  • ScrollableControl 在整个控件周围绘制边框

    我正在构建基于的自定义用户控件ScrollableControl 现在我正在尝试在控件周围添加边框 类似于 DataGridView 的边框 我可以使用以下方法绘制边框 e Graphics TranslateTransform AutoS
  • 从 C# 访问 COM vtable

    C 中有没有办法访问 COM 对象的虚拟方法表以获取函数的地址 经过大量搜索和拼凑不同的部分解决方案后 我弄清楚了如何做到这一点 首先 您需要为您尝试访问的对象定义 COM 组件类 ComImport Guid InterfaceType
  • 如果我每次创建粒子时都强制重新初始化每个粒子,我是否应该使用粒子池

    我正在 XNA4 中创建一个粒子系统 但遇到了问题 我的第一个粒子系统是一个简单的粒子列表 其实例是在需要时创建的 但后来我读到了有关使用池的内容 我的第二个系统由一个充满粒子的池和一个发射器 控制器组成 我的池非常基本 这是代码 clas
  • FxCop 和 GAC 疯狂

    当我尝试分析依赖于模式和实践 企业库数据 以及其他 2 0 0 0 的项目时使用 FxCop FxCop 抱怨它不能 定位程序集引用 即使正在分析的应用程序 dll 是根据其编译的此版本及其在 GAC 中 如果我浏览到 GAC 尝试选择相同
  • 不使用 DAO 压缩 Microsoft Access 数据库

    我用CDatabase类开一个ACCDB访问数据库 司机是 T Microsoft Access Driver mdb accdb 我可以打开并使用数据库 已经这样做很多年了 if DatabaseExist m strMDBPath AJ
  • Makefile:如何正确包含头文件及其目录?

    我有以下 makefile CC g INC DIR StdCUtil CFLAGS c Wall I INC DIR DEPS split h all Lock o DBC o Trace o o cpp DEPS CC o lt CFL
  • 有没有一种方法可以在 TreeView.Nodes 集合中搜索 TreeNode.Text 字段?

    像这样 TreeNode treeNodes treeView Nodes Find searchString true 但我希望它在text字段而不是name field 我不知道有任何内置方法 但你可以使用 LINQ TreeNode
  • 如何将8字节的十六进制数输入到char数组中?

    我想生成以以下开头的十六进制数字序列07060504003020100 下一个数字是0f0e0d0c0b0a0908等等按这个顺序 当我使用unsigned long long int并输出数据的前4位 这意味着0被截断 它打印706050
  • 检查字符串中是否存在所有字符值

    我目前正在做这项任务 但我被困住了 目标是读取文件并查找文件中的字符串中是否存在这些字符值 我必须将文件中的字符串与作为参数放入的另一个字符串进行比较 但是 只要每个字符值位于文件中的字符串中 那么它就 匹配 示例 输入和输出 a out
  • ASP Net Core 属性路由和双正斜杠

    正如所指出的here https stackoverflow com a 20524044 3129340 URL 中包含双斜杠是有效的 我有一个使用属性路由的 ASP Net Core 项目 一个名为GroupController用于处理
  • ld: 无法对非 PE 输出文件执行 PE 操作错误

    我是操作系统编程的新手 我正在读一本书 其中给出了一个简单的内核示例 如下所示 main char video memory 0xb8000 video memory X 为了编译这个名为 kernel c 的文件 我在 Windows 7
  • 如何获取 EF 中的实体更改增量?

    我只需要获取已更改字段的列表 数据存储区是 ssce 因此没有可用的触发器 EF 是否支持获取列表或构建通用组件 根据上下文的类型和生成的实体 您可以通过多种不同的方式来完成此操作 如果对象继承自 Entity 或 POCO 您可以使用Ob
  • 在运行时生成可执行文件

    好吧 所以我想知道如何创建一个程序 该程序创建第二个程序 就像大多数压缩程序如何创建自解压自可执行文件一样 但这不是我需要的 假设我有 2 个程序 每个都包含一个类 我将使用一个程序来修改类并用数据填充类 第二个文件将是一个也具有该类的程序
  • 是否有普遍接受的 GMP 替代方案来实现任意精度? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 在寻找 BigInt 库的过程中 我发现了这篇文章 Microsoft Windows 上的 C 或
  • 如何使用 C# 以编程方式识别对方法的引用数量

    我最近继承了需要一些修剪和清理的 C 控制台应用程序 长话短说 该应用程序由一个包含超过 110 000 行代码的类组成 是的 单个类中有超过 110 000 行 当然 该应用程序是我们业务的核心 全天候运行更新动态网站上使用的数据 尽管我
  • 布尔实现的atomicCAS

    我想弄清楚是否存在错误答案 https stackoverflow com a 57444538 11248508 现已删除 关于Cuda like的实现atomicCAS for bool是 答案中的代码 重新格式化 static inl

随机推荐

  • 谈谈我们公司如何做Code Review

    研发中心团队越来越庞大了 开发人员越来越多了 和他们聊天过程中 发现开发人员对代码技能的提升很迷茫 诉求越来越浓厚 只不过一个接一个的项目交付没有给他们太多停留的时间 在这种情况下如何给团队营造浓厚的工程师交流氛围呢 方法有多种 最近进行了
  • 35+老测试员生涯回顾,揭秘无力吐槽的自动化真相…

    不知道从什么时候开始 软件测试行业就和 自动化 这个词联系在一起了 对于如今的测试人来说 几乎没有人不知道 自动化测试 甚至查看各大招聘网站 你从任何一个招聘渠道来看最近两年对测试岗位的要求 几乎都要求会自动化测试 而不少人一直认为手工测试
  • JS获取阴历+阳历时间

    1 阴历 获取阴历 start getLunar var nyear var nmonth var nday 1 var nwday var nhrs var nmin var nsec var lmonth lday lleap 农历参数
  • 海思麒麟985性能简介

    海思麒麟985 SoC由中国台湾积体电路制造有限公司打造 是麒麟980的升级改良版 率先使用7nm工艺制作 是对上一代10nm芯片的改进 主要在功耗和性能上做了较大改进 麒麟985大致参数为1 3 4 CPU架构 8核Mali G77 GP
  • mali GPU 官网指南

    1 简介 GPU 图形处理单元 是一种专门在个人电脑 工作站 游戏机和移动设备上图形运算工作的微处理器 以前GPU主要用于图形处理 现在GPU的通用计算技术也得到了飞速发展 事实证明在浮点运算 并行计算等部分计算方面 GPU可以提供数十倍乃
  • 【python】python如何从一个文件中引入另一个文件中的变量

    直接和导入python的函数一样导入变量名即可 十分方便 from target file import variant name
  • STM32学习笔记五、RST复位

    1 STM32硬复位 STM32片内已经有复位电路了 可以不外接复位电路 复位引脚一般不宜悬空 所以STM32在NRST引脚内接了一个上拉电阻 典型值为40K 为了防止外部干扰 STM32数据手册上建议外接一个对地电容 如果用户认为内部上拉
  • java后端接入微信小程序登录功能

    java后端接入微信小程序登录功能 前言 此文章是Java后端接入微信登录功能 由于项目需要 舍弃了解密用户信息的session key 只保留openid用于检索用户信息 后端框架 spring boot 小程序框架 uniapp 流程概
  • 【ROS】虚拟机VMware 安装ROS 一条龙教程+部分报错解决

    前言 Linux下安装ROS真是太多坑了 如何在Linux下安装ROS呢 博主带你少走弯路 目录 前言 第一步 配置软件源 1 打开设置 2 打开软件与更新 3 选源 第二步 设置sources list 第三步 设置密钥 第四步 正式安装
  • C#中断点不能调试问题(当前不会命中断点,还没有为该文档加载任何资料 )

    1 winform 程序中 经常会出现的一个错误 断点不可调试 1 当前不会命中断点 还没有为该文档加载任何资料 问题原因 窗口所在的类库或者项目在应用程序目录中 release或者debug 中只生成了dll文件 没有生成pdb文件 例如
  • css如何实现盒子在鼠标点,掌握CSS定位,才能让“盒子”飞得更高更远更稳

    众所周知 前端CSS中 盒模型 浮动 定位为必须掌握的三座大山 今天就来聊聊定位的那些事 定位是什么 先来看看哪些场景用到定位 如下图所示 凡是有盒子压住另一个盒子的地方都可定位 因为用浮动做不了 如果盒子浮动 会并排但不会出现有层级的观感
  • STM32F4 IAP

    功能实现 正常上电或复位后运行用户Bootloader程序 检查变量存储区的标志位 如果标志位为APP FLAG则跳转到APP程序运行 如果标志位为BOOT FLAG 则运行用户Bootloader程序 等待接收文件并准备IAP升级后跳转到
  • (数据挖掘-入门-8)基于朴素贝叶斯的文本分类器

    主要内容 1 动机 2 基于朴素贝叶斯的文本分类器 3 python实现 一 动机 之前介绍的朴素贝叶斯分类器所使用的都是结构化的数据集 即每行代表一个样本 每列代表一个特征属性 但在实际中 尤其是网页中 爬虫所采集到的数据都是非结构化的
  • Android界面设计:Material Design之下拉刷新

    目录 下拉刷新的核心类 SwipeRefreshLayout 下拉刷新的核心类 SwipeRefreshLayout 下拉刷新这种功能并不是什么新鲜的东西 所有的应用里都会有这个功能 把想要实现下拉刷新功能的控件放置到SwipeRefres
  • 【每日一题】字符串中找出连续最长的数字串(字符串、贪心)

    题目来源 牛客网 链接 字符串中找出连续最长的数字串 题目描述 读入一个字符串str 输出字符串str中的连续最长的数字串 输入描述 测试输入包含1个测试用例 一个字符串str 长度不超过255 输出描述 在一行内输出str中里连续最长的数
  • 数仓建模理论——高质量数据建模

    数仓质量 数据模型的概念和意义 DIKW 低质量数据模型十宗罪 低质量数据模型的影响 数仓必备技能 1 建模基础 实体 2 建模基础 属性 Attribute 3 域 Domain NULL值的处理 规范化 范式 第一范式 原子性 没有重复
  • 不归零法编码、曼彻斯特编码和差分曼彻斯特编码

    数字信号和数位化编码的数据之间存在着自然的联系 数位化存储的数据表现为0和1的序列 由于数字信号能够在两个恒量之间交替变换 所以可以简单地把0赋予其中的一个恒量 而把1赋予另一个恒量 这里恒量的具体取值并不重要 如果是电子信号的话 这两个恒
  • Struts2 S2-062(CVE-2021-31805)漏洞分析及复现

    简介 2022年4月12日 Apache发布安全公告 修复了一个Apache Struts2 中的远程代码执行漏洞S2 062 CVE 2021 31805 攻击者可以利用此漏洞来控制受影响的系统 该漏洞是由于 2020 年 S2 061
  • 2016xctf一道ctf题目

    首先是index php
  • CUDA中__syncthreads()和__threadfence_block()和__trheadfence()

    作为cuda小白 我看完书上对这三个函数的解释 仍然不懂 于是做了以下几个实验来理解这三个函数的使用区别 我们先来看看 threadfence block 是在干啥 这个实验非常简单 A数组的长度为1024 一个block的大小 先往A 0