CUDA C:线程、线程块与线程格

news2024/10/6 1:34:26

相关阅读

CUDA Cicon-default.png?t=N7T8https://blog.csdn.net/weixin_45791458/category_12530616.html?spm=1001.2014.3001.5482


        第一百篇博客,写点不一样的。 

        当核函数在主机端被调用时,它会被转移到设备端执行,此时设备会根据核函数的调用格式产生对应的线程(thread),并且每个线程都执行核函数指定的语句。

        CUDA提供了线程的层次结构以便于组织线程,自顶而下可以分为线程格、线程块和线程。由一个内核启动的所有线程统称为一个线程格(grid),同一线程格中的所有线程共享相同的全局内存空间。一个线程格由多个线程块(block)构成,一个线程块由包含若干线程,同一线程块内的线程可以通过以下两种方式协作,而不同线程块内线程不能协作。

  • 同步
  • 共享内存

        线程通过下面两个核函数的预置变量来区分彼此,预置变量代表着CUDA在运行时为每一个进程都分配了这两个变量,基于这两个变量,可以将一块数据分给不同的进程处理。

  • blockIdx(线程块在线程格内的索引)
  • threadIdx(线程在线程块中的索引)

        这两个变量是由一个名为uint3的结构定义的,这实际上就是CUDA内置的一个包含三个无符号整数的结构体,如下所示。

//这个定义在vector_types.h头文件中
struct __device_builtin__ uint3
{
    unsigned int x, y, z;
};

typedef __device_builtin__ struct uint3 uint3;

        根据定义,这两个变量可以通过下面的方式访问结构的成员。

blockIdx.x  //线程块索引的x分量
blockIdx.y  //线程块索引的y分量
blockIdx.z  //线程块索引的y分量
threadIdx.x //线程索引的x分量
threadIdx.y //线程索引的y分量
threadIdx.z //线程索引的z分量

        为什么这两个结构都是三个分量,因为CUDA最多支持组织三维的层次结构,即线程块在线程格中的分布最多有三个维度,而线程在线程块中的分布最多有三个维度。CUDA使用了下面两个预置变量来保存层次结构的维度大小。

  • blockDim(线程块的维度大小,用线程块中的线程数来表示)
  • gridDim(线程格的维度大小,用线程格中的线程块数来表示)

        这两个预置变量是由一个名为dim3的结构定义的,这实际上也是CUDA内置的一个包含三个无符号整数的结构体,如下所示。

//这个定义在vector_types.h头文件中
struct __device_builtin__ dim3
{
    unsigned int x, y, z;
#if defined(__cplusplus)
#if __cplusplus >= 201103L
    __host__ __device__ constexpr dim3(unsigned int vx = 1, unsigned int vy = 1, unsigned int vz = 1) : x(vx), y(vy), z(vz) {}
    __host__ __device__ constexpr dim3(uint3 v) : x(v.x), y(v.y), z(v.z) {}
    __host__ __device__ constexpr operator uint3(void) const { return uint3{x, y, z}; }
#else
    __host__ __device__ dim3(unsigned int vx = 1, unsigned int vy = 1, unsigned int vz = 1) : x(vx), y(vy), z(vz) {}
    __host__ __device__ dim3(uint3 v) : x(v.x), y(v.y), z(v.z) {}
    __host__ __device__ operator uint3(void) const { uint3 t; t.x = x; t.y = y; t.z = z; return t; }
#endif
#endif /* __cplusplus */
};

typedef __device_builtin__ struct dim3 dim3;

        根据定义,这两个变量可以通过下面的方式访问结构的成员。

blockDim.x //线程块x方向的维度大小
blockDim.y //线程块y方向的维度大小
blockDim.z //线程块z方向的维度大小
gridDim.x  //线程格x方向的维度大小
gridDim.y  //线程格y方向的维度大小
gridDim.z  //线程格z方向的维度大小

        通常情况下,一个线程格拥有两个维度即,一个线程块拥有三个维度。如果维度数小于3,则多余的维度对应的Dim变量成员会被初始化为1。

        需要特别说明的是,上面谈到的四个预置变量只有在核函数内部也可以说设备端才能访问到。而在主机端,为了调用核函数,可以自行定义dim3数据类型的变量,这些在主机端定义的变量在核函数内部是不可访问的。

        下面的程序验证了如何使用这些预置变量以及自行定义dim3数据类型的变量。

#include <cuda_runtime.h>
#include <stdio.h>

__global__ void checkIndex(void) //定义核函数,显示本进程的预置变量
{
    printf("threadIdx:(%d, %d, %d)\n", threadIdx.x, threadIdx.y, threadIdx.z);
    printf("blockIdx:(%d, %d, %d)\n", blockIdx.x, blockIdx.y, blockIdx.z);

    printf("blockDim:(%d, %d, %d)\n", blockDim.x, blockDim.y, blockDim.z);
    printf("gridDim:(%d, %d, %d)\n", gridDim.x, gridDim.y, gridDim.z);

}

int main(int argc, char **argv)
{
    //定义数据量
    int nElem = 6;

    //定义了两个dim类型的变量block和grid用于核函数调用
    dim3 block(3); //注意这里使用了构造函数创建结构变量
    dim3 grid((nElem + block.x - 1) / block.x);

    //显示block和grid的分量值
    printf("grid.x %d grid.y %d grid.z %d\n", grid.x, grid.y, grid.z);
    printf("block.x %d block.y %d block.z %d\n", block.x, block.y, block.z);

    //使用block和grid进行核函数调用
    checkIndex<<<grid, block>>>();

    //复位设备端
    cudaDeviceReset();

    return(0);
}

        因为printf函数只支持Fermi架构以上的GPU架构,所以在编译时需要指定架构为sm_20或以上,如下所示(默认情况下,nvcc会产生它所支持的最低版本架构的代码)。

$nvcc -arch=sm_20 checkDimension.cu -o check
$./check

        程序的输出如下所示。 

grid.x 2 grid.y 1 grid.z 1
block.x 3 block.y 1 block.z 1
threadIdx:(0, 0, 0)
threadIdx:(1, 0, 0)
threadIdx:(2, 0, 0)
threadIdx:(0, 0, 0)
threadIdx:(1, 0, 0)
threadIdx:(2, 0, 0)
blockIdx:(0, 0, 0)
blockIdx:(0, 0, 0)
blockIdx:(0, 0, 0)
blockIdx:(1, 0, 0)
blockIdx:(1, 0, 0)
blockIdx:(1, 0, 0)
blockDim:(3, 1, 1)
blockDim:(3, 1, 1)
blockDim:(3, 1, 1)
blockDim:(3, 1, 1)
blockDim:(3, 1, 1)
blockDim:(3, 1, 1)
gridDim:(2, 1, 1)
gridDim:(2, 1, 1)
gridDim:(2, 1, 1)
gridDim:(2, 1, 1)
gridDim:(2, 1, 1)
gridDim:(2, 1, 1)

写在最后:这是我的第100篇博客,回想从写第一篇博客到现在,也只有短短10个月,但是发博客似乎已经成为了我的习惯,希望自己能一直坚持下去,努力提升自己的技术!

最后的最后:感谢我的父母和小李同学一直以来的支持与帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1320252.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何应用基础故障编排?

基础故障编排是保障系统稳定性和可用性的关键环节。通过有效应用基础故障编排&#xff0c;组织能够更快速、更智能地应对系统故障&#xff0c;从而提升业务的可靠性和竞争力。本文将介绍如何应用基础故障编排! 1、选择合适的工具&#xff1a; 选择适合组织需求的基础故障编排工…

9. DashBoard

9. DashBoard 文章目录 9. DashBoard9.1 部署Dashboard9.2 使用DashBoard 在kubernetes中完成的所有操作都是通过命令行工具kubectl完成的。 为了提供更丰富的用户体验&#xff0c;kubernetes还开发了一个基于web的用户界面&#xff08;Dashboard&#xff09;。 用户可以使用…

Mysql之Specified key was too long; max key length is xx bytes异常

问题原因&#xff1a;mysq索引的字段都太长了 767字节是 MySQL 版本5.6(以及以前版本)中 InnoDB 表的最大索引前缀长度限制&#xff0c;MyISAM 表的长度为1,000字节。在 MySQL 版本5.7及以上版本中&#xff0c;这个限制增加到了3072字节。 如果对 utf8mb4编码的 varchar 字段设…

python+torch线性回归模型机器学习

程序示例精选 pythontorch线性回归模型机器学习 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《pythontorch线性回归模型机器学习》编写代码&#xff0c;代码整洁&#xff0c;规则&#xf…

【操作系统】实验四 进程调度

实验名称&#xff1a; 实验四 进程调度 实验目的&#xff1a; 1. 加深理解有关进程控制块、进程队列的概念 2. 体会和了解优先级和时间片轮转调度算法的具体实施办法 实验内容&#xff1a; 1. 设计进程控制块 PCB 表结构&#xff08;与实验一的结构相同&#xff09;&#xff…

超详细整理,Java接口自动化测试实战-rest-assured

1、关于rest-assured rest-assured 是一个能够简化测试rest服务的Java DSL&#xff0c;像ruby或者python一样的动态语言去测试和验证http服务。 基于java并且兼容了groovy动态语言的特性&#xff0c;使我们像写脚本语言一样去测试http服务。 例如&#xff1a;你的http服务&a…

范仲淹:文能治盛世,武可镇山河

北宋景佑元年&#xff08;公元1034&#xff09;年&#xff0c;范仲淹回乡祭拜范氏宗祠。在苏州祖宅住了几天后&#xff0c;范仲淹决定在苏州南园旁边买一块地&#xff0c;在此处盖一处房屋&#xff0c;待老迈时回乡居住。 按照家乡的风俗&#xff0c;在破土动工之前&#xff0c…

Note3---初阶二叉树~~

目录​​​​​​​ 前言&#x1f344; 1.树概念及结构☎️ 1.1 树的概念&#x1f384; 1.2 树的相关概念&#x1f99c; 1.2.1 部分概念的加深理解&#x1f43e; 1.2.2 树与非树&#x1fab4; 1.3 树的表示&#x1f38b; 1.4 树在实际中的运用&#xff08;表示文件系统…

软件试运行整体方案

一、 试运行目的 &#xff08;一&#xff09; 系统功能、性能与稳定性考核 &#xff08;二&#xff09; 系统在各种环境和工况条件下的工作稳定性和可靠性 &#xff08;三&#xff09; 检验系统实际应用效果和应用功能的完善 &#xff08;四&#xff09; 健全系统运行管理体…

Hadoop和Spark的区别

Hadoop 表达能力有限。磁盘IO开销大&#xff0c;延迟度高。任务和任务之间的衔接涉及IO开销。前一个任务完成之前其他任务无法完成&#xff0c;难以胜任复杂、多阶段的计算任务。 Spark Spark模型是对Mapreduce模型的改进&#xff0c;可以说没有HDFS、Mapreduce就没有Spark。…

架构简洁之道有感,谈谈软件组件聚合的张力

配图由腾讯混元助手生成 这篇文章介绍了软件架构设计中组件设计思想&#xff0c;围绕“组件间聚合的张力”这个有意思的角度&#xff0c;介绍了概念&#xff0c;并且结合架构设计示例对这个概念进行了进一步阐述。 组件聚合&#xff1f;张力&#xff1f;这标题&#xff0c;有种…

两位技术领导者的故事——英特尔和高通

对于科技行业来说&#xff0c;包括这样一个现实&#xff1a;上学、工作和娱乐实际上是未来生活的一部分。科技行业也面临着变革&#xff0c;行业内发生了几起重大收购和管理层变动。其中两个最具影响力的变化是英特尔和高通的换岗。具有讽刺意味的是&#xff0c;这两家公司在过…

UGUI 鼠标悬浮UI出现弹框,鼠标在图片边缘出现闪烁

1、背景&#xff1a;鼠标悬浮在UI上出现提示框 public class SpecialParam_list : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {public void OnPointerEnter(PointerEventData eventData){TipBox.Instance.ShowBox(Input.mousePosition, value);}public void …

改进灰狼算法求解:考虑需求响应的风-光柴-储容量优化配置

目录 文章摘要&#xff1a; 亮点&#xff1a; 研究背景&#xff1a; 考虑需求相应的容量配置&#xff1a; 风、光、柴、储微电网模型&#xff1a; 储能配置模型&#xff1a; 改进的灰狼算法&#xff1a; 基于余弦规律变化的收敛因子 引入动态权重策略 运行效果&#…

长尾问题之LDAM

做法&代码&公式 step1: 全连接层的权重W和特征向量X都归一化,相乘 W * X P (得到各个类别的概率) # 定义权重&#xff0c;初始化 weight nn.Parameter(torch.FloatTensor(num_classes, num_features)) weight.data.uniform_(-1, 1).renorm_(2, 1, 1e-5).mul_(1e5)#…

初识迭代器(Iterator)——迭代器模式——迭代加深(后续更新...)

学习网页&#xff1a; Welcome to Python.orghttps://www.python.org/ 迭代器&#xff08;Iterator&#xff09; 迭代器是一个非常有用的Python特性&#xff0c;它允许我们遍历一个容器&#xff08;如列表、元组、字典、集合等&#xff09;的元素。迭代器提供了一种方法&…

02什么是CPU上下文切换

上⼀节&#xff0c; 讲了要怎么理解平均负载&#xff08; Load Average&#xff09; &#xff0c; 并⽤三个案例展示了不同场景下平均负载升⾼的分析⽅法。 这其中&#xff0c; 多个进程竞争 CPU 就是⼀个经常被我们忽视的问题。 1、CPU上下文切换的概念 我想你⼀定很好奇&am…

软件开发人员,参加各种行业技术大会有意义么?

参加行业技术大会对于软件开发人员来说&#xff0c;是一个获取新知识、拓展视野、结交同行的宝贵机会。 1、知识更新&#xff1a;技术大会通常涵盖最新的技术趋势和工具。对于软件开发人员来说&#xff0c;这是了解新技术并将其应用到日常工作中的好机会。 2、拓宽视野&#x…

遥测终端机RTU如何选型和配置?

随着物联网技术的不断发展&#xff0c;遥测终端机RTU在各个领域的应用越来越广泛。RTU作为数据采集、传输和处理的核心设备&#xff0c;对于确保数据的准确性和稳定性至关重要。那么&#xff0c;如何选型与配置遥测终端机RTU呢&#xff1f;本文将为您揭秘RTU的选型与配置技巧&a…

【ros2 control 机器人驱动开发】简单双关节机器人学习-example 1

【ros2 control 机器人驱动开发】简单双关节机器人学习-example 1 文章目录 前言一、RR机器人创建description pkg创建demos pkg 二、创建controller相关创建example pkg 三、测试运行总结 前言 本系列文件主要有以下目标和内容&#xff1a; 为系统、传感器和执行器创建 Har…